From ad58e726e53e4eabf124515084c1b9aa1c1cb4e4 Mon Sep 17 00:00:00 2001 From: Bruno Casado Date: Mon, 20 Jan 2014 10:55:54 -0200 Subject: [PATCH 001/146] Add some tests to new wrapping image --- samples/Sample_03_Image.php | 107 +++++++++++++++++++++++++++++++++ samples/assets/img/flowers.jpg | Bin 0 -> 126991 bytes 2 files changed, 107 insertions(+) create mode 100644 samples/Sample_03_Image.php create mode 100644 samples/assets/img/flowers.jpg diff --git a/samples/Sample_03_Image.php b/samples/Sample_03_Image.php new file mode 100644 index 00000000..2d6b8bcd --- /dev/null +++ b/samples/Sample_03_Image.php @@ -0,0 +1,107 @@ +'); +} + +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); + +// Create a new Section +$section = $PHPWord->createSection(); + +// Behind Test +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_BEHIND + ) +); + +// Square Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_SQUARE + ) +); + +// tight Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_TIGHT + ) +); + +// infront Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'marginTop' => -1, + 'marginLeft' => 1, + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_INFRONT + ) +); + +// inline Test +$section = $PHPWord->createSection(); +$section->addText('Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!'); +$section->addImage( + 'assets/img/flowers.jpg', + array( + 'width' => 400, + 'height' => 400, + 'align' => "center", + 'wrappingStyle' => PHPWord_Style_Image::WRAPPING_STYLE_INLINE + ) +); + +// Save File +echo date('H:i:s') , ' Write to Word2007 format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); +$objWriter->save(str_replace('.php', '.docx', __FILE__)); + +echo date('H:i:s') , ' Write to OpenDocumentText format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +$objWriter->save(str_replace('.php', '.odt', __FILE__)); + +echo date('H:i:s') , ' Write to RTF format' , EOL; +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'RTF'); +$objWriter->save(str_replace('.php', '.rtf', __FILE__)); + + +// Echo memory peak usage +echo date('H:i:s') , ' Peak memory usage: ' , (memory_get_peak_usage(true) / 1024 / 1024) , ' MB' , EOL; + +// Echo done +echo date('H:i:s') , ' Done writing file' , EOL; \ No newline at end of file diff --git a/samples/assets/img/flowers.jpg b/samples/assets/img/flowers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dd55c65e0e8ebc037831766083f7349b71b6f603 GIT binary patch literal 126991 zcmbTddpy(q|3ALYC(>ytV((5AX;)<_VU?q5KKkV0*^q z3~b4gC9t#L2Ta)ovxF^Mx>WTOd@Tn*SFB#KV)^nFYgesWxms(;5S-?Tw} z{l@j{)@|6jVdLg4a5!8|Lv!2KE!#G2fp1Y=WXUq{f0nOUvtq@XE$ZvkxBMS}DL=tB zu3ma^*?*QT*#%p=amlicOO%x`1Pr!h1-M()4gb&AlBM7tSFT#UX6-ug4FwxuOP4HL zwsiS2)m?+{4g>GQmTz3KY3HF+D>pk_S+(oVmcxHNPg}kF^t;b+$7aEvBUc0dUbA+q z=C@y(=%RYW@XbEIq&n?1s@7O78QS~sQg-0{jH|9rIp*(&im2P z+1EcXI5a#mIyNp8&Cbn>7bMa})w!0ymi_lw|9i6k&$%{&b1hxIeA)6Hc!DC60~9_Z$Djb{_)M5*6Qa9N*z5*_>?1OvtDGHUDgYY-+5Am@u+CAyd-ZM)!o^aLB;pK zQNqG-{t*nPDcYgO+3WA3l`ty@$7au@Z&tF}$gK1aOEbG&qLGW^qk4JLH0J&nNf1UC z<3nQ7Ib5DM`|uGtmCSU(a+hi)F5Gi)*Lnm$@LTh#cW^i|&WT{W#E~MsC95s8f_Y0( z8u5F5oSnBN;jYtfL>A;^FOE-$A9y)nbupIU>}uo!bsun{)mPHVhJWr#&rE*-$7@l^ z>g0GhmYP$KP3gNJMWMDVQMYnzKDp7sI>icq)5>bg1-vE7%8~1=v&6x{YUOJSd+7J{ zX!@%k21o@QybN=(Ep%|LO0z;taDuF0aL3H_2daw~EHz-DJm~bJS(XmY>Sxoy#kFAMOz?tY19)>EtD>>~G(|5nJ%S!n!(5He^vE+u$&SP7x}{im>`&T0ZxXL#H^?o=tgLi##PMB< zax!l&_YAZfaj;h0eYLD1Jw5%wUOG7JgI!A4W$QRAl~GZ4C@buXcr>>?%*WZu(qoBZ zI^#xU`kRVfShI07&)K>Dbb2~j{V{%j4o-T@YGo$Y09XsPGd+u%_G)Q51HV7l>8ioL z^aw{SGO&!+S~IEvR=u_yW9d4M)B~>?06VRri+sRGTCMy%*oG|_arVUAT<)Td0e&-f zZsMZoD|9iyp;m)j7b7dwGH`7XUQ7LSI>YA`mrPC|!*U0k9hLV4bR9RYKP?o2-z>`)m zmvkSW^j|R#u5SS1KjNx^0ZuRd71uxuWWj1W!-skPZ{V{BYZtU0-+AP1F#kV4Y-xTrvJ$VbV)izkGxW4W*GR?-`jwH{tJ1I z%}{XxYF9=L!zb?n$cOY-OI1k${zlPzU?BszDRde*otB={bQL>G&jI$v{)LQla2RpG zzS@-&e;Xeeag_--g1_Aek|h0ACBp&Znw699=D0LFSqB{X@~Zs+@;sKPamwjAI8$=- z64x{ao%&+?tTW1(>-q}BLcX)h+l{0*Duk`vm!9^@vx%CPp3cNXgS2+Cvce`U=M>R% z+;cKvTYjYo04f*XBoMqrkd2c|_tP0S=()=-01R*-F+f^hceayJ6LK!#5hc`g28rA3 zL4EG*VzlKG8GJGma~9wt$nL8KA8XGcw;LEmmG3Lz%M^s04V|N z3~kS#7KhbtjIVJ^`3yRKr&{X8swsGgO7qE;wKGk_bpZB3~(JeEjLgz?i54a z%5{`^22ha|#$AOi02Beh&^Lg8tKM|va(}(L9TDto5r}ai4gK3DscVw%VZBNXwDSBb z$m9!pi4u0*Jy`6^W(2N7Ol?CFN0hK~LrTI-#o~he9Pv<)A}y_(RLzplQ554+GdoWXxiHrBIb+}2~h4#5mdMc{; z081zDe*j!#b&8=82Lib1Cfrp8xWBSQ>yae@61pmyRUyrF)&_|M=p3hj|1#{j7Izc? z1f9dX0Bm#s5110Bvb$r%g>*`FYV#ns10MKB^C=1GQ? zhX{|*d$220RF>1WWr(Eqj^u1_rk!}#&-q}C9eHA`qk&bz5)m3d6sf^O zN|>K4K3=xg=JkGIRxSfysqJ@tD^?9Rfz;s)F+-WXaoH11iWmpB>~bD0ycb(32>Sbg ze6x3umshrXC+T%5t(f&ay82LO5piLNTC*5_zIP%7FeE; zo*2ND1@N0I?25@u2kc)oCl{6;+58pUN0nzgHvk@m^UhsYeOp@&pnE{4g@asAx44t= zeYt@eaoE3H@sUiav6DD*uT73Y;f4CM-^h57W~h#H0L@541@Mn>Jl0@8T}46>R}p&T z|6zLrK+7ULmW)?Fod&Ym31cn)0Mt-Anaed`VnMK8cXsB?HIUV9|8;JG7V(hJloS=M93FtQBNn91QUj_*~% z5(>mFXv${MtOY<9kst3kI1`|+3mT^6$ShzXMvj(BDW)?YkkdqXe?5v`!P4zHAR*MA zEE?E^P@k1-q&rvv0K_v;Ac6GQ=T_ql3ZbmDoa44^0C)vUU$;6qIa^?W{@{`rAaQ{) zFL0ZhjZpxrtQVP?oSh4{aJBvcO4{Rpffb-Dpg)ys zlfiH9FaikvrMof|7{Gd4oPUvxOYy#C^=4kV?oUIZy`2>CBX%gdg-Anw4~t*i`E%y+ zBKj+9?O3NcPNM^T?|F|0sj;+94xi;s&d7cX_IGOH6v{(KF4x`JLh@?9s;K_P7j;aG zT|QycI;V3~=Y&-&=RLcQ)RW1^Eh1!r^1Bt=FB4Jrx1r55A6dt;pDmcg2JK}lVU%y2 z38t0n+$bsR0&kS|^=k+sIqYu$spI=|c|}#uA|RNshAtOW=61kbws`>*s7cC&Rv4gA z!vW6x;^`DyDbO<3SYU4z}6r6>QXuSN+M>qnA>{o7Tp|JwP3l2{+Qkto+>t4m_sv zc*bPGV;~UH)H65x&RzNe;soID0~P-IFh4O&5*<_!b0ZTQQ!CDOzF=Gnu0khLxnl;+ zt~mxPe<@y-!WmR48e`{PK)(22e{NZ#3Z3SY)6Vo<%gK0+I1g<=_4srE2?k`(c|1k$ z9{@`CoQ%Z}omDiirc(TBzv8oU4FHxOYvWNMIKn<7XR?&ARGhe43EQEB1&|A|x;q78 z+E4U4te@v@;nw7AMMjOR|-)HLl^jy(39V7y^e*JP}qq$4HM;T>3}q$a@}Zxj7>0T@`nsgGXVVd98#6 z36f?V0CW3IYy1b4e*|NvLn`qL5CAA{#;LbgpEv+6^fWkXxo&*Q{^H1nu*5bGsH34sU!2p1f@v8h^ zHMRJG3pGtt3eZ4Rx`0jwo~(8*$M7_ns|I4GNk!m)#rrUE?_D^P$Iv^a* zs*b54xp4HZrL0lvyD%|?F5GD+sV;Id6myn{?8QL^R$^P3e+4?fH_=-oQC}g?qiqlW zUK}yC>?r=p}R)CpKU{PhWN5EK% zr8|TP!RL7ICC9tf2F;NUv0HTrRdi>U08sv=N9J(dc<6tJB!fK%fpF1zd%+`wOty#KHN z%2r(r$i9;sfbwZmU)g5`N3C4dt&1VJeI-3`MQ9dGnJx}EP`6D&3XXgZGe6-{9~?O& z({1qkp@jVml=r>3GU}2hQxNW(A27$|lGNH-(91diRs*X|LId0a;;Gl`SiUrglepciYZsNT+19MPJwHIoc#&dJShjxzi1< z)!i$c_)9Kv@NRu>rmsGc%6gpHhgc-I*C}thpTn=DN`4!xuT-!|j8mE&W z!3^24piTszPN6@U25|c>gU^KmNQc zdbWk~{*tF9^i(7H^1(DFFx%>fp5D{tjk2QMO4#kv?i+hsBpS`ZmXS(W!8_cP+tBFM zaf|h_Iwn&e_+=D@NBg-WKKDbaSi?OEmh2$%&}42_a&>VyB}*E_5w#c;_RU0n2tkX7 zraokdOQx<(+aTrnJ)TDAyuvLPy!xQawx!vQ79$5!v)2TPN!{IDr0Rl7&#NvrX>TU_ z(NS~uOU8OPHIvw+e*ZhShQrb)rf`) z%`dKvb9V8oq33p3Xi7_e!7;Zol41zLHtR63gVgxKu5GvWm5{UOUW$2`3pK|Tw6O5k zovG=$E^xf=_ZY}S)sva$R&+ck7>C6INpaCv>&K+os=j0M`%CMnVhzb@qv3qf0LxTh z9X&NEe=#wtu||5=a@cKHnzgIU;N=MS55ZiwhOrX%NL^>JtuPyEywg!XY~@+!t0|vj za^^y$Ym=(>&9~#u&9c;p=1@KBB)e5kZHn{@Nt{ZU@8ecF=Y*_HiM|pUoyJHjc}6iU zrSxk5ql9@|kGU^KM(g+y+GzATY%9G!jOtCB2nmV<(CSw=->7Eu3zp_qiG#Y(?QSpS zcO{PypB1al$JRlo-C`A~=%Z!b7Dux`mFwM#s2NG-E#_&M0wnRHIOYQ}$e(ZdsIV4$ zLG@AJpS{~FsUA=dJtZ*yfE{d7!n_nYb}T~(dyd0b!mgHQMpcR-0|7Iu;Fc10Xq`VB ztvEs&UAwocGrj304-3cNYT%9E@>T%EPs|_Ir2ma(*u$H=F_h9 ztX%AU8iC=7b$7QEmrO)od)AH?cYb__3VVw7J@O`2{HDq+1(5>kAFsG+Yt6;lChk3q zlXYoi?ZVkoc6n)H-Pxfi#Wf}D9WFx&%jZwF^)*I%ZfIGb`?_Pi{9xhp8GSBkB)K5O zbOL)_JrVopWoLdo4()R*Ms(z&b)ayKI-Sb0c;QqTtyoEMY(W?#Y25q)0 zsbg)h*<=%V%hzQ30AEI%;$=%{VqM9V{uIwv*9|>m4pJNKj*H>b8VkK;M=X`FbHc(T z#3JjhTnU?*VVx{dd`C&k^^etGCizZXZcMv~zX#Pw5yEwSnlTpJdM9H2usfQ4s9_5o ztuDZ6+UUPOvI?a9@rn7?icTiy$px$NDq&sKjlRtUJn>_f% zD&XKqYoDl=m@1WWlrS~lfkxAo6Uk*qw_lH$(sbp|j(Fk*NK5=^8i5mKCtO>zM0rDi zK-uA>UA78X@`b{vN^038t*l51bB%YZ#!p6>T8rjFBJ@1xv+8@3fcnWJeR0Y4>-@kXFzpC3_AF_r$FQdA z0^_mb`|ea0+UiH@>a64!iP9+x zfz=Z6cD?2)^jJ#EB`ImT{R7Q7&T`o1Qj+K94&J}~3Z4Hv#k+|gmSe1pQFyW}?%R=J zRs!c%*$L;UDy<;$Bxj&X)PAfNEghb~xzwvWmk7iZf?9L$Skw4MAe|2ku~r#>R)j?D zob-~u6j7h2Y+IxmK$WS7fVac-TUa+|Q0t}~yA}|$U-}(FU6z0owJ^V`myM+8i=Q0wO;EzZ#kl#vewr4l4B;tx z?#uK&685Ik?jm|B#m8=-E)@N+csS)Q(CltnU-P07GHr_x>C9Bb!dhLeEBHVDoX@?C zskuwo-9}{T`Aa91FpPo02(-0sglOJc+9;9Edh;(Eg;nWh7i4dzH6E{0|Km>ETQ>Ba zswxee%|HVarw0Z{szRK*G#%u!s>_Lr)(Jl~fLv44Z@;S3CL4pwoTttFC)R+`hh8FS znf<~M9u->A7OfX!_LIaxZz3u-^y0Az&&B={aqG~m{=~#v`R;)?g}W zW^YuU*>8TPzZM8l8`7N}xb8Qa)tn6(l2C7N{SGvH??+ba-WN{U51$!?AgY>bCa&FS z{cM>M}IdC(|01uVFL5VgF8niM1X7Iny<-}#3> z)#;qK7_pl-YR10vDctOXjm$;JLoeEigOsqpT#fEK=H%XLl1!e_%GAXM4)|{3dSdJx zD^R!p*f5%?8Si@8^sL|87NVsNZLzkotw7@gX4p-~G)|l7HCkevy$ghZlAsJ=1XfON;H4iIAm^i*=QNs6>5omYV8`UB~Tdl zqs8}nFW=J)KOnn~p2)3$>cX4m%ZtuUqWi88P;H~BdNMB}&{6tbh9v@8wEP8$aOQ|% zlwKt6l5DfZBX$YvH_1C;$n2NmgcRKv_0+UmvKka(0sXN+KT2+;C{b$$fQy_D9Pm6O zET?7llDw^bp{Iyxd862H zr=b%{_I834=*|{V>XJk|nvMuQr5qAn0{@TUmFMuw~E6 z`I69VYoPGMUI&Da8wl4&L=w<<+-sE!}b%`Pi<%E9$i6&oxYHsOcpo&+s*~M5-Q@-PZzp0D7r;qmZelC>xJJywdhG({AIz7##-h(Ud&#nC%R)orPD zkHMYX@~f_AD7=@rQtpMghuQP1Mkd%M_h$*cxW$}?HYKdh)in+^H1hX7^H9js|G>46 z#m|u9xIim9zV{w_uGSVhnHnr6fS{ zIQkbuQda{VLM82J z8yjM$>TB9{EF7wI7T;6M_Fudzxhmn%lT`ZuHuEcyCR?sZ! zy-XI*Co+1h(a^&JfwRTs5R*^-Pqnf?)8OILILY&Ins6Q=pC!%kDum^3PDkrnvxU}a z(_X=~_sS|JaT<1jviQ}hMjt4U)l|TQ%(WdY9Wka&kc5kqD1>(PV7(G{sg%t!5GF7c zWoo8{@)FOm8ZgjzyQCjc>JN%)x5}q?KQA1?WPi=>RAim_kt=mWf2}Y~JAm=w+>tjn z{}zm9*~jXfZ}*?8YeYgJVUme)+$y~3<>3flMGTaK1_AwPV%VLD?$d5Z56sF=SM?*i zFV#WiWvrjiQgSR&{3H#z9dLUBP~<5I-jYj7*a|J~ZNDdVBY)HO)Z?O?#)49{x%Z~d zAWW-7$ow8_%>^yaUX-@|WY{&g)=~ziX*$(dhFh$U!F@nnFO1|MIX4wB@@N2w-!Bn%CVO+feZ@UCCYSTwgu zwL+lU11LbSE#ifghx7JRqk*~mOPK+^$XI*nl|N%ZTzT0x%5aa(T*Md;8@6n3Tj_gu z`&)tFjRkb0CsS%GsnLml2~AT&QsVEu}A=F@M_ogi?=;{AMR zLZjsGvD*UIkj9u^(Tugu$1Bz=VT76^G@;p{UO%ls_FYnL%=cgrgQ+t!-12**@d?9E zp1S!^Z!(q#fW-D=f?W&)J@V2}zQ%LEugt{<`c08p;E#m%l&>mP!lDBcJ8--x!CvW#@jDAS&+e= zLmq)%%QL%{EjN!k&t=`4sK0F(eVsBX=5#~m^FQN)`SzmQb7Q+?dzk=*;nTV%iC>hk zYwXt2E4iQ~_8^L|HM7uEm!eae+h6@~N^Zii6yFMH^e9lm+{HZ>{=FnVTpE5iiTn9H z^X&Z&8qaeFx1#TT`B|sLf{M*5Qw(rj6sSl=+p*S3()w#T3ct;+ockS4p!b&>j)8anxe<(WJU~yLs~YuOX#KTX zkjOr4Y-S#$M`46z*HACMR&+^S+Il)|P_)jQoKSdhW7YB72jnJc<40RDnu!O5je7}? zXkTZx`f^0;h44X~L_xf9WTUKNk@wf(Zj4zmN>MySx<0RjZN;004IZ%$g+72T0Vr1i z-u z_uXDP;Ay?~MsRoCI;hLO*X+spphtB+Vcu{-HsdQ%za)0{OFn@%t5Ga7+vJ88$|^du z%KC7UL`%Td0n+&K4^&JlMdJs1l$h%S4Os>Gj)c!ZA#M}63*wK+YZlqU_A6A<7v{|h zB;+kgwGn7nm{v#1O^idHr3}{H2^@ASt`PJN$X06iSUW(CN?2AvJJIt$g@U|yel6h( z3+0!#Hj~0jdDXNH1&!N0Nw4csuU$bGdFmp6yy@v$^jfri-+2wx9FJW*B6>xqGj31q&QGo@qc++X#nr`4I)ar$u_3w4b_?f;zuhVvT)y`9btjDb zd|FWUCEt8P&~Npcioo>ZG2^!8cq}IL*^UITCkVFR)~3d=p3&qh4#KB?r3Gs@gpIlcFxdne^nT5 z+Q>to8O>p52^T2-q=Ch=<&AzoE1XeTUB53;T-gg3Hl#p>5a8aA0E*vGF0~iE9@kyg zJlqtB=)rl~?TD*}zVIG>E8}pQW(6-_Dq*E#jOy_!n;QuukSw-LvqE>7aAm|#X{q(y zv|jARUMrDjoyN2rDB@!OjtKF6u7#N-XFKwWO#k7{q1l74L8F7Rcr||BZEA*Y-G_Uq zr5oXOz?2xIX@f`vJ&bECi&Wp6Eh*dl7}7$W;d#R=UVnd)H%1ME-2hM!;|)5S&5rbI zz%9ionwF&r)e7&VL1+MyQB?i5TcSYc<%Q4@^zAjF6tOZDe6b?BirQK*))-S z^eUvV8w9&g?{a0Gw{$MvGC;gWg-K9 ziASEWwEykTp30amyB%H@S>;sO%08jHMrdE<3TX(4o$SOvJApLQ6(6>P-q>)8F49() zAMn%NBYcSNY)=RwiHV+GOg64m1d*U!??`^Q<$kFK0{g^1`}yK95gvU5sF`HHRLOP$ zZXoJwZoS6Wg+uP6RDXr}%q;L`IOjx_bCm*bQT@|`x5gg1n8-mAW&V|>L1J+PL2PJ$ zbn$HJSu`J7D^bGi710(4h|bB-CXQBc6h@$!AK||jUG6o8v=$9`;)jB$PdW(Ms%l-M z{1TxNXR+S2VkFj_{~32!ep^v!<{(_x&|11v3ERSo8dP+3*U9Qi$O^lt{ody@-#2i4 zX`0dZe(UZYiISfZ1j+vsZpJe^q03YhC}_w;@wZ&+SC2@9bPQBN^n5Zz{TyoRyz~6) zqD(O@NqS>fx;XXczoa^_z&qDN<$l$jm!agRDGtrU5-$d+y0NpoE8Rv3%eeBUq7t3I zii~<{i`W+IIE|PJCH1_f5__))kO&9`S&FWY!z53AXvL_1Ck33%ZD!N923Pdq9?VfD zahrR67gLK2$I%m|jRz4wStAX|pC7O0&N}cqCpkyv%vdMHIN#j+7CC~($3CC8#N4)<1v*&7Trj8oGDcP_?`#EVsSzz0E4+^d!aD8N9nB8; zH_jb1(iD%3QLlPO5T{r>a0}KYS;*h_$VG17hCH|OGN*|f&51Wir({qw$7wD?9IarM zBKsQG_PPgO`q3REzc<8Ma6yGn zRS=PuyM_nb%CkQW6Edo%1gf`YIJ*G73${nW7`$-A4KB>E|Hv)hHV&o- zU{N9YxZ^wsp*Q};C9e)S*bUW>cmNX{q3;WourgfZ#VAY|voU=^2^;Egvf=J-Hx4ru zqou@xS@cX!p(jZYFl~ocAGgp+RQN~DyarX(1LR`P+*-bdQ|HO{@~XYvz31Qgf~eEI z9+(y+eta)fHPU)O`jo3#sb3@1k3^5Xe(z=%1ZB0`mT=eGqi z@7gDXc8wX4xJ1U~RWpVo_7SvvB-uh+Zk=4YU;)xA+B(_1*iLh157$Wvd(X1AlfZ@DeKq?d=~GltA)n zxdJtEIU}HF)^oo=BhJ&}$O_BNLRw&)@XWP;NgBdqIEkZ$c7CL`&%BQ9KF+ffIOrfV z_(Vl}_?lAgJ#C}}!~umHi|e(~o8ipzuDCD!S*^&-21Q$=xv+h6h0`ZdZPJ@7l}XP? zC$5GgcJaZYmQ@)1C~+NF?NDt~_x7u{OTYqQ{r5$30a(pUWN)W|u~M2b%JswX+Qbk{ zYFQRofgDE*r}mUzwShW$R6Kt<@f6Ds;oWj?;y8(;h=R2tvbGQOQD#x8<}$BB zK~z8Pr-;*5tx&{oO&jPzdzMng;u)ER`(By((|G>$NQZR?`Yx1(IBHti#x_TLw(lw{ zimER!R19vi^T$_!a9E#yufl>i<-a^ZA+`n&M~snluVIW7pPx5#k~d` zWY5M*qxI!%soz*G$NQWlRksezQ-pJ)q3F9)JF=h3uVwf8en@Z_<9C3vDe*f9`{ap6 zxqbgOxeX{40HuPB`&iKSrIuOuEqv0k#0m1S+@OSj?p`Y>#tW&0!EuKk=ia^;)D4Y& zcKYnKEx0-3wL|nz=z?&fGsz;JGqi41KZ8)&CmM>>_M}G9uremoo}|5lRR(6+AsDO%=Tat zD|tXtKfPNS@}&G`qNbzuD#ejU;b4Dg(Rz3G{7p6DJo@>^i0$)}H?u_s4&d1d*VI5i z%f1uQpg;;`f!^kGXGO-bsnfp3J)p;XjKsER4AcRY@ia;2Pm2SHF2v?QU*gQsP8;Gk z0GwCKuiGvttUni~o-5>ZAcXdpti)kw_z>13TP_D`@kVL(XCSfW`A<6UN6;t!=^WDq zn;)dcFUW3t2|V1cGU+vlW%jrfbsx$HdS^CS(wM@CV4R)JiDc`s;~Fw1u6m)+MJe4-0`v9%*2=F%ezbZVs{7Gh>+)ZDCYAn1~zUY9^#eP zhnjR8B#p6Vc0WgRprMde59hU`)1ZbAD(pT;z#Zg%}74L>b$gd(LMz09)z zV}_#VO-7%LvrDD$)r&bhznf=mZ{ z>p?3nS1ST-qbkuGC+A43dKAfu&0jt7XF$N$t=U)(@n_nRkHgmoN1Rd&6-EUb+WG$k zO|3@R^hf*X@?}E(zi&j=VWVn`o*~(%{GkfB2JdZTnqy-A#5-}D(AWSPb}Z?w>8(a< zL>FkNkK=qll!!756Q^`>^8Dv*6XP0xx2I|-UZch`ggE)r1=^U#UD2sku^fXvxG7#` z9EM=bzY&Yr!9njFW z91gx)QAo{m0B-q?8=u%z76EDTDrsxNms_Sw0<@2@@&M7eFF;^MFdEqL)x8|K|Fi5S z9PO(&b#3-i#wz>GSkIR1gHf?~t+1+Og4plJje;V|OjjLP=i#{>EjY zgBJ>M6Z=@NYK17_F>GLN>rgRQcxOwWZE4xdA~J0v_k+Y|ZWg+DIOG3;jGr^5bg!A0ea} z{f`L<%Z72F2|MOmIm7oAf8xgkG<~-zB=7# zKZ_0)5iG8?yHRe>Q{cg0ZdrS_4GUK^3RD|ItS|3&>?F1vyTzEfJH3D8&umK?L5KI1 z|5yoIX=Y=QfqZD81NzHrR*cLb+=~@_xqA3~Ft^tWGsr#SHYGi3Z@D{ra+J35#Wl~P z#6f2lj`W&!+=!)^rstn;4f5HrM@&v#+~NH1xFR{JKTSju>G)Xs-XWNDFgc-j?;sQ6 z$2o#X3F))NezIYg{Z#J6vDiL2e_nf{=KC!6nE%~xi!W(W?+B$s^ZpM-EDc|@Al9$* zejH*ZyaNg9O&DZ4YO#Bq-=%w$d;J4oO>Oj?A#P!7aS_pdP?9@Ud_N^?Y=MUm$&|24 zHx!+CtZfyUX`G_ha_jVjbIjBR4}cT6#+LxAk^|0Ji8~fZq ziZZgZj`OTPQZIglHQ>cr-M;Q3^2znYY+3Savr_dm79MP~eh>?}Z8ik4^afOt;5bLw;bZ$mpi7X4KTN6vEuQ-{ z!Ir$sCw}J|Beq$lcTfBy;W-I<@~F?=h5CvJq`kL%TcqtIP=}<_0F#&JjtL~4+i8Xw zOv>N6QHwEyNw>jcii>yu8IfB;QG>mp)q7A0BPnVb{eJcm8#5Dn7pV?6{|||?5L@h? zKFbNxU(6YqJ4<>uqu0urdJSj&I0Wse3&HTk2^8N@CCq%6EvgKQF~IY*ssCDk*ASc3=T9Q@H(%+VBJyX#C1z4Q`rca4h+tdweQyD=##MG{t2 zq1rCJl3w=uPdJGS1|sCqrLR$N55|?&H|UY4_H0vu#6ZFde|b&`GbPsws$)P5!NcAh z>!Y?THsB71?kBZddpM7A#eY}*G5&}5Bp#06p3|dx@U+&O7uZMB2%}5};C}LdK-a{PKoQJC#oQu&d&6n{&h zekb%bNUgA4RHNNNYBX(Qv!97X+XjFLt~*kT33G@}~>5{S_97M>nWFmtc&(UX(@KDz8cBCOW})e_bN=b;#;V!#NDgZ4#)XT) z*S_2rjD1LO#R;eUHKzwvc{`672v zsLI0xei@7Xxt<<+>|T?+GkZ6e@mjJ=^y=qR zwFLQ3ZtN$n^3>2cm)1A4L_t{y+8}*r1GaBLdGakjT4*Om3(%EQx;_J~Y0W6K^vYe$ z>4B$8ST}aw19SR#F4oAphV}hWyn)Lw=h~zonEC?o(#D%!sPyfMXR?F}9Ayz;`WI&^-p zqp3c~-6SL`?ou27vEQbdO7v_ye$MyjFmZHot&YUMhj@+;y7pMX?XVY0sPgshgcWn zI8;TLou+|bk=p`EH0uFvXA2|WL6p8|)`~)*lrui@N>CjoNA#7gJ1^9XnTFcLF*Kyi z0tx1n^P!$`V)T}Zp;3--K)$gPB$%n_h+4140-p9=5%EZJ0`B~xQJ^l@1n=r_Y zX9foipw&|iMMn!5HJfbACtJh&&H3H7eP&Fj{;kQcM-PqhsQj3jy^5*~I%YV0L`Fk} zM1d{G(MA85zJvuJL?1?g{z?KEAb&wmyI};{mRuB48?>A@`d<;TyH2>hZyo?;yrj4M z1mgVdsN;+64o~U?ZF~RzWKFdr92rb5)0hnTx1IM^>ejA=m8hOeyitq*E6(i}JMp-y zO~x|?d{Ul*C(pNCbaE{bR9A5x3*G&S5uHqCKf$64N*jC=CH4~pavnhX!Tm<2xHgV1;;6`|(~#>^9Y;WG64Kj>Hfd?z+{fxJb%Cfjjvr-j%exQ|b`E--Z5 z#VD&-e*+^+1>$?oKRiEywLSDhlA_wsu@GLqgqE)`%r~WGM=*}bZG5goN%{jeVhKku zw-7T#4!BP~3K<8|JP$m2(usM=9|LN{#?xLN{$ZY@W^E!5bu+tDUcdK9{y1s#F*}T9 zO@;$^cj=oh8%e0RaXy|wCmw0-W6$o+8+n>NrS97|@+~;8{1Sh@HaZh1oT%@hf%%v- zr`0Z8AE!tr$cifgNc`j9c^$AA7}y_|2lA3gE8%_3FaHIV^#+2}D4M5as|$ z2$^%Q-{JTD+0op4&)H|~wbxpwhwxh)@HK4f3i(s&ek}O zskCWfbJn6@ye!t_x*WVj5AX|kX95y><{at0vRDL6- zHgwC@4wsUe*{FD@(Poz86$i(9ZICK+(mcuGce~s}mr@Ra)s@;jUOiOI)z_vEki!^u zy|J7+Fp|w9sAA`#m6f|{KY-e~161|DaJ9d)J?-Eoy+Ot6yctyP_4QbGtBV&wT~k7G zd~cz%_9qdd`fSgGO$N{T=8$>8ruDg_2f?Xn+1ZQ&G9SMK9d7CJ6`ZVsGL^D&rKxA01dVszwJ9#aM81gxW zWwQDOA*4%!$@O{YQRZfs<&&L#^8=#Unf4B^TPS9HV5DLUzb%$V21*%scGP@WGl-7; z@)SU4DT%4++oT6QXFlA-7<@szI}*1#o0m!BZkardks;sqXErHr*k{&>X9krMxw^b4Pi0w#-t1QAtIy*EU3>k#i$IU{ zg4~@rb>G=a$`~`tv1JshBZkfnm}NijM)MZIZ`e$4uch5~q`YoEZW7?rRKvFp0n6v| zGx;7Hr{$_hA6q6*Hq1Qbx%QzoAmCZT}nwj1`B2bsQ-9yr17ea3po|Jhcjf9Q= z#Z?OCIbZ+tv;c58+xMUC)9xvYnR;ELi1e_apbbdp`@&B7v&x{O|MRc8Ei+7IL7$zt zb0+@4Dd^ey(7k5v4*=@1+TmQdxh8adxXRR-Uuhd_vP);x;!onpta>>UMYJVZG&+1% z`m<1)8{ZNrE71-SHD6!;vSO)c5W}7UkUqHiYb2I*6Z5Zmt4`KJ;$MyV-PixS?1$5J}X8T4tLWgARmg^&i9GmPr6)YmkYv6f_5} zL>z41!MxygiU`73Y(3df9`09kF zp!Cwc<1wQqiVvJ ziId1$=?@uTP{hu&#p?z59Ayst1Y|r4H;Ds!_X9YPveH|lXbu4Oz=bK~O7$|&k1(>B#T0bFclQ`(RR<$D zo^bRzn055o-#tjy>6!+cuejH=oR7Fdb-i;uGc3HL=4vl*?&dYniCeQ6kBTdU07+-M zT~M_o9w^9~6iPH+#6|I*#zoZqC+9~EDLaiyTygi201xW9n#FO1UyaIafpw_gm%{9D z9YE5`$YNjW0?d02CtDR);Em!FxnPzwPzA@tU?l$mD=I5Xf-IGI84}6=I$2VyvbeD^ zbB6p~)1xgMfiFe9%ZHD(-wh<~n=i=LaU@14Z3n6+=#R$T%$azTYoEY$$+y_3a|Z*} zOJxXeHppTDZ&5kxc>j-q?qKLC>0J7EaDq=2x_f9OoC8>htTUbyg2{7w2a+@9F)`f?$0l{PPNEG3|M_7xjH_8x(D6%Kpg1MX z^4%?TWsn%lNGXv%28KlT==*p|8x4589^1Kkv(5wt!7n)1S&=7^VrNLSE=0G{<5@2g zs&_ZJ4~tztg7)Q@{}|_T-iAeDiZ;D)6z6m%yG1CId|UW~ut}$5@f%J&(JCS){?V0xDq>;Ix3MwyrLQN=DH8yCC$4rimMIJ5! zz-kauWP^P|uiDrfkjm+eVo9vj0Koea{u}OU^kI_XCL`Q;{;MkXyGJ-DfL#1mN?fNF zIO!47_T05YVvKmlB3*HU;i}AS)pu4Iw7;WCGXmWVC04X$UAyn!BzJYR1r^N*4JO1* zx}kNPv#-vU_^SToX1B&5&x`stW%$f)p?_3TQZC2uI@POp81wWTKGtjEb|RgS4=HGR zTmrTom?P1HvWXJCmBbSN9;hiT^-|PMW7W^vH=4`c965L_Z+yf*0N6y~%ZqRvAxIte zdFr;_LA1ujQnzzkQ>2T@mlge}Ts_8URd;TQ>o4o4HCqj~f4XQNv(@v_{Ys-zPyDKB zB^mebkM2?e%BS$c~x+Yj<)$O{2w4vt1 z(r#v@1>t#sy9(^Gen|fnyUUWh_iXR$4-cLuocqKv_SSiHPG$N>IAmQza(h4$+cIWA z@}h7uhgQr0XJ9Z+?_pD<12ReQe$V~j4_7f>l-(-uOFDTr5)XCnKBdjBBY_F*ty;;P z&2bwaPyDWP*H4sNl?2k7aTlEljMaa#=pZI z;UQa;hn5QwQ$y7z(D;cI8f6p|c4lu7p0M&kThg}IKJ{Lm;DK-Va+fE5!jAK$B$Kgj zV5u^?Au*nX0LN{rLYs5dR@0G9&9<1~4j@i4$hMC=$#lkn|IuRs-u@jKx;or=pxgB@ z=_l&g)xvOP68`y29URjQ9xOOkiLWCAcNE~;$dJ=tmFW04wq zVyrMj*8uekif2chd7~60Ho-Dg(UsJ}>WY|sr6c`>jN{7P1~yjd{mg0F@=iW^M<7nu z*xAJ21!SZRoMggL{K^xH5f?gQSFs1q zX{-Zdh~kMo{i%Pztbbc^CO1#l0Z(LJn5HeR1CkK9snSq!AmJf!MlUONoTppl{8z_> zMybu%FvW``e2SK$H5oquKgES_;%@6${_c`l_?xJi!P_}&2jd3eiIRo6*v%ZiN0Zt? z;1X97j4OkQm)UU=NTeMUAYnQk+~ChP?W?jtgvuKZ(HfevjjOH~ZF`}hs{aB@lb|6+1;P|gOj*zX+_f8u&-@tCp99}3(49;J zAWxA)76@lAyZ91d$pPb55cOO^UHd;D~py^eeLUG#Q6 zWA34Thje3sO!Q`B{$4>PRD)tJgALbu>p0NNfkQ8!OE?w5^ROEUgl9SF%=7nzxRlNF z1v<0S=)5xn`HB^(OjXZ>Ng3|CgSlw-SO8b805l>ERt{#G6HJ2nBKk*l;K}p27@x`l zn(jEst6oi%Y9p<}Ib(nK@6@?ez>B@Z&{QSKcp_o1;7FyKat?4JNF`&qJ1!Y8nP6V> z-wH5&<@_B_uteV$FxqVV)Rx}^;%d;_g_~jyrm@TM1dK-4z4V{$BhG>D(zw2MpEA@x zy931W)IW_+IwiBHHpnaS$CVNS;jTmUG@}P4w@c<_8&2Ju?Rh&|?o&25Lw^j?n`XC8 z&8bAxbpyknx`4MQBn*8%*-Jzov3OwltJjLwJa!v8AFj^o)_Yz`eq(rm@p~E4)1KWX6}=|!;TP1a1AY)B5(nAbSaYGi<|rc+DX`0f&>!-I zO4~doeophh3>9Gx(Q?(%hWZ1h)uq$V6C4@0?Ws#cK}kKxl#UwYa5t8t_QR|oon96x zVb|lI<5iKbyLJygIPUE-qoLs+PZ`UxAt`4NzJb?i8KmC@OVdU^4JJJQT zCfRvrU=O;dD?!qkPB{+3SIPvDz=Ui?z{FZPQd>n5oax-@V ze1v};pO55DEb60Vk!V4_VH#*ot8#ABU=%SA4KC3)I9^+F0d@D|49jIy41=-O$=*ti zXt1Ym7hod4tT4H}?2r`TRi_S@2UmL97M)G7kJN#Xt*{ISH0?NjyaNzO{{8&fZ%)|w z2d&OX06V#&6f_`IN2cArZa;ZK4lxh>VtVAf*|F#jq%F^C_2b*#ZqZyvmdas*HlmuP4%SXvxawAOa8g9!LR3) z%$vWx0KayLw!g-ywMZ?Qb~Wz3$d85R5WYy)@&b3{N2) z8H*zKZmGytT}xn&-pv21-}(HP75|wg2_+rD^PlITwyne#SpC!7vz&nGiAU}_tX>8V ze70}u`M)M@zfXA>6{NxN6AJTAvS;33PW+UptPVHLvvY(8#^5EON4j7W>piuow~>Y2 zQrPTjRr=;fbvHAzEgnq3700R=ZnCwB3fg0|d=gS9mjRF?vgw;5-w+L!T3s7Gz*&gB z@4K7sKNuI$Q5os!nab%CM7dwa{B@@9qpVZ}Y4{%ivU6SLGBwOVxR&uF zzCiVY^;OIHaDIuIq+xJI`LNr6upS7L z)3Vg}6aJeY1`X&PWR?`tzNl~|&Ook8jLSp|bwgI~Z55kG0THAM-aVFlOdc$)DvSZh za7QwP9BfCl)6UyOu=+U5$e_>+y2uyZJESmiLX$^W!mv5|brUjg@V`@|O=!EUj`8%% zipqOqgt}M3_OjI&wJ&G$4nfhE6%UgFnVvT8Xx^kySF$|WV#*FSnBEetGi<#Mx7X+X zpNsXZ@Q2YF86|I7Nci@^DIm_|s@R}{zl@xg64Ai?7{ZlNdsq!nYaO#K!ts6%k?OoI z2JAjb5hxLFjp?IKO=;aL=YXT+&eCDRNj8|ZAYkeJ=8cQ-(1qP&nd>B0U5%jXNs1V3 zMu+b=<}No}Z(G5r08pEf`c1CjKJ>1tGYtc0T z1H~7T92Z^+U+SJraJ|BLWx4EM{GjAGA*($&A2|K+OHd9886k)EQ|q(#Y*Q{IUov!N zqy)cPBBc1=q5Xbdce0W`5})1XYZ@5m-%|jLWdS8p^F(WcQAiFuB4q*Z2wIVe$;0Ht z_rL|By~444%`f1tD9gdqgs#5|?7Lhp^sr&s{e3NEjT@tQD`B=6e$x^s)*U}#O% z{wsV`GB>>PWZmNV#maejB3oaRIQdin-o)*pKybL`-`snQrZwsp=y7(~b%OyByoCA> zZQIEgz2%^;J12z!AH~ti;BNGRNpHZH72sfkB#o$7yEifxBN&0aTh7d!v^+o7?XEk% z*vR>pdMEeIAoRErB&}f7s&q&JOrX@k_esmp71c?4Krc>m)W_XE={Z%p!h|PIXm)EJNil zU4wbwQXKSVS#gQhz}zYtYX=)gbX>FqIF0T&P|cjbtca&A_*A%tY2Sjb8T@p-dfnxC zWiQSXM|qQT<3RE=A%Zy#DnQbNkYGqHK{D=X`&|BmVl869zT{F)vOrI1av?%ExHXG9 z2Fl1p{~=aw9SZs)A>$Npa`DDT@W(tOxWoi|w?b>LDu|Y<#v+a-Qk%>a-fb(dDN*I! zm_FB;vf$a}P0Tv;LE^o!4Fd&W*(0< zh+O6%Y5`a5_VW5sw5n2_)G|mJg2Z`=XB|m@EDxIkj~y78i{-T>d9^I)x0S-&tz5L@ z5ytWzc+0U%HlOOGExNb#ZW7L(Gh}ru@Dwms8n%x%-;$blvF6=0}%auu6o5r(0(yWo$~qI8xuSjPA12N=Y5N@G7yZ zq-CG}e;_za3T1>>1q{0*d8L|>3m$f`!>0&2a%{ol8J)0B?`HYyq|BIE%RBlkGV8z_ zWj{^4tAUtlV#*GwN$~NitFdZ$Rq`*K1eY#c5#WjJi8T8xcH46^dw`$X!D zH9p%jN-I2NAr9JW~I?t*4bzp4QnB+DL@ht-`u7)?mf4fT`pvP{~3`1Q)t1lNnPX>mmz zVY&vZxpO2F;#z1n@(p{RI%Mu99G;F*z+$VKRWzO7;)(G$p*Nq!FFE2`frgl9g_23- zLrv=Tgi+4AZX~S;z7U=jM+n0m!;T~uA`L*M&AG)oE$R+=C!K6CpoN5OdK_!U0kas% zy&TEteEaX`d8~bZck9Y*i}=_fVEm^!GKIYDcto$RgGWN#xAUoaKcgq3Ff&KQJa%{yua61xN^d84RACH_@r zP$rdpC0VIVMC~~ zP|Hy|RK}CmJmw?A+ieOx6?2KsC$lV7ibC>R1!L9B2u9{}D?A2y7-r1XHi#C17P(6` z6N~v*JdFN&tsBe&%O57>Z&T;lXKV8gv|?s==~-})zamB7_#Xr}RM zp>pV#*yf%1kt3i+xyHT)hw_7zTQ()Poe5Z_uQCOw&Sv0=d~V}i#Zu*PF}rxmJx2Gj zh;djJ_Pevgvstgek?Cu*TSLc#35Z=i{CObQAmmnFp|fqq!p-wJB?cb(5IBWjA6W~1 ztRu{_Fq^WIQNTTb^Xs01V~Ws%KPb8_u%d%n9bi*(Iv(+e&V1hLcSH`m$mMlKA+U8;0J>-1^&N%bt?=0EU~AF8A9d zaOzlx!Jiv7vwl!dgWvJ;e`a_hPb~NrYRiHVF+nCzuvRU%^Wo_631>@DHz08SrPwxf znKW>b`Kaq`I(Ec^L;jf0gh$W2OS4BMw|4c{io2Tex_xGz%M~vk9tnw>xRGoSlzpLk z$^54~PH&eC?*=<$jB@V4OcsqP3{1GGjRpCKpr}L$Z|hAkE%3ivjOT@!z$bUCu(S)9 z`-(JqDgkJMH@aGkkj~2RN@|8OVDs4G95_6ua?aM#q&blz#%UhSO{}K(B4jL}E11I< z^J#~*!GI!=R_tHEG|U33cwD`dRj{N;JIwyc<|Z3 zbcyhWFvu{)7OJfpm)8!vzQH$a_kJJmgzgT2_8evj52&c-#)f%*@bxgkB@*%RB|DM( zx#`Oh4)B%ScU7BO_qqQ)>yyI=$yA7`80nmegnTGHyi369do(DYs|tGwU7n3;z8bIy zCkK6-F=m2!-AGi{HPZ)X{KKRPoaJcQXe(+jsjK@S4^3PS9nIlH5;np_(l33L0E|(` z0lZu4J_z4rdqVGAi+?)ks=D=j>y|8wQ)Tb9@L2Y1VG3-zqZdoO3h;(aVKxfg__9Jl zTkr*tqty|AoGPVfXhwC7|j>>W?oCc={>9l3)!X$6W#Z~J>t%d74R2!PH zquH%VQ0i8fk;+gV{qjQoA?Opxn@I?q7BOk9?`ocyNxjVqD%LOAR*E{7Pmw@h<#-0L zz4u!V&hCE3U=?S3dAf7U7wfE0EamO$}O!WCvH&T1n=+E z4uLrb^)>;?e}SLh_Vzp&ef#JwWvj=w0IjDsQh87FgzQm8yR6;rx_{;0Bpiq$6LEp^ zHjJ#aO2h15W!1wO-BF+Wl5El}XA7)h7z8m@AWo+@s zSZqF)$~Yxa2_U|%GkX>IO?8B99rilB;qboAw`hHwF}!TGNdOuci(dj&SxCsST<&{` z0O-nWbmnuk#i``&G#wV@dfRs!p&M|R)6c0$R4W0%Em#f24ew-AuN$i1NlTN8hg=MD zkgB#4v|m48fCXu-UsfdEVEYbXojd28UBbiG3RzXq&wYhxJCNf}WVY*TD+!KGGh{Fh z{DVCpNyIDR3|*s)Fev$asalrX0uPKB_KgDA656KtlQX-pp?=BbCpqfZ51;~fK9w&2 zB(lEa*FF?k{$6YCy7NXua>}EHF#Ue@;Zf)o`ZeVU2n)P7g@mdkEbe}yq~G%Hjoib} zasfK?Mk_^Cbf5Q%HC#<(AVV2DnTtMWQ+_O2YY&CJOHemv?m62a3SO5YZ;8vH{w9I@ z0rFt+07F1~0I4zP*X+7yDNohyrJwx3Vd6CA;-qS%QS=%!umb`Pa_u2yV*SAaVnUcQ zcQ*?tM#tcW;Dys(1N=V?oRgu;4f^}qvi}P@c6}vJfwkaPlS_KJ z{qRrN3{~HF$N^{9twrHIK7Xcn#yf(P!jBWN#3jfQKyq3F33O`WG!Q6P;GSVJmG=X! z`5u111Ni17hM((}rbkhxn-}2zAt1}Jk4yjVp0r;gNg#J?ETrIpqE)1;fUkZVS!Ccl_FT;)Psf>zLUiwx5i1dt80z zv&*p|#COn^{o&uVd3rybLbg>Gwj{dicU2D~j20Q7pAG{pH7XMPL$c;AIdws6X7>lR z#1*-REZ4XbBb=O=6Zyrf({s~jeITz_Asde02raLkSl*#4MGq3?Cwa`xR~9CCV@P`@ z(95hO#7>igZ;hS{X8a!{J_b{X*hL{pCA;I?KD5q4_;qZ(h2x5XYp@#a^&G1;*Tz9G7RVq|gWtPHG%gT2~ z`Z-R5iI3EMPFzmdf^_}~u6+UE;c_&%1?cj#i0}JHQsb1+JVrB-5UEVqRYk5$cwlx^1$zz*EJWdSy9%VLyCIa9iR@eB2*bB`?&1T`O8J@H6-JAFTLvfcn+@`cKv+k+ z`yyCS>@q(`Olul9#W8B6@b8)Lhs6))9xecY<~ROj#a3?)g(ExEZ=W21c-IwRht3@0 z^y!6U&fWqyV^3pi8{+fYWNt}t55roUUs-_U0}E7m)uI76JDtQvO>1Ihjt-#Phd-0RY31Pjad9(+CIm zb}J>CM5GH?OAv5I=dkav_!n#VB&W~t*DYbC1b5vFh2I6?w|_naP^nL)1L(JnkAr{FyBkba;qkM$WiB`b)^Q z{NBXlZ}0;UGK{&Hp&9|UIy(7A+#dtW?hsSKdh^%r=;GPxqf@wbeRnvYrB zg#S2ZGj+ixK;`(RK}pnv13KYvJ#$d)@G^S#6ktFEYo-zeIaDMW$SMj1k)zN?_!7Fn zdSa+|r2wN> zR+fDppw>E8`o1|R^`)xiZ%zZ{c$@p(SU?2^$HskG@l-r_eXapZ(mZL|vS4fj#gw_3 z#o)rDCQ6(9H72+*=J(O}F*US2-UwphZPv2gY?MiMG_X z!KM3oGq%Ol^aaJe7Ccw1S+qH4C>CgF(1~V_)KV8qm)7H{E#$9xh4(NPlh6U~i$yZ< ziO+%}66ElBS(24;=g`Ugm8wr8;{JXYk`Pj|#|;zJ#iKL!*wx+312)VcL4P6&7E&h% z0uoIdFsXJ)xMM>o0ZIrU;}S|*sOo2W54zeGuke9o`>H{83Ws!#g;aI^=*NhSv<5je zm3KXVhuqn_5Ww1mk+bz1K*7c;Bb#zCjxT}&etv}6fGZs!tL9`d9US6~>8p5g?=>09 zSA7h7D;KBM=oW-VA7}&WG(F}DMU9!L%2wJgca>+PmE$>8d6Uy|m|0s;Ai{ts!q70~b8%#(NWs(w96H3cRM6&C%X43CQ*nMXh zV31XyD%|#MKL~^%UO+b9kgl5F2Y0nURsp;o9oa+jqX$NAUFz?}DLK`xSsq}}rim0c z2YB%G-hU6z2spC&(xVg2B<2_ll4LPszg(%hB)#W|||z$d_%ce271NhyZBj(y%x z0_^p;H_Apo4YrK;bgw#}i{rrpw@JaH2*-NKvx+r&MZnk_DH_o5)eFVa^EEO7mv3@6%TSvmS_@K zXWXklhtTzqv^|*h;RYB2ZD=5sIzKpO#rgEh{ahMQa4}wC?h?KM7`zHK@r$fES{1R$ zt35U*7G-$LT?q=N=9S3CLjIDxr>{1EI_y~@^dL?ESwG>g5ILR>H>#ko-|e5>l122d zvmBkM*1{!f6);J)Y~yafTo22vsV5$ZR2-JhdHJ4`FDqVQ1|!>O-?PoaM>h8t@UD*a z+h!oUIuL!5*MfOGxpR$p`ug^NrQ*krT;pg)o5Js0lH>IA?8kGn2JgO;sFFu9r7GKgar8zRm_k^yu7e*Jo4 zS+F0FBlQabnaT!v^>>xAhJ(_CV59wSLku-ZpX3ZsWg%rpWl`VUSVKMFV7AwIKq;j|?hd&V!=!v)9l`z@t=4i*404ZF z4~zY6O7uR_8ki+#)eZzw=9nVv9A-mg{+dTbhj|){*^q`1@=TJAkp`6FfY{w*Iky-p z$|07{^3A2qBwxc2INIhNBZctqSi_Zib1C(A{rQs1^5lHqN7@k{>hA<6FCWF8K!6X3 zOQ50jpv-0M>$23^dA|=*cj6V9X>oKo+@~QJGt0aGAJW2s4YP8b{zS*}9YKs2&ii-M z@73mr+|_wXtmY=)hJ1X1PF3fYc8oTE%L}HeI0LHFKr)n{Yn8oTKjnj&|8H)qV@h_J z-|%!JHLnD;oMQw<640fE2%zw>$W#W@3nwLSCtLu`>@(mcN52VL*@`v2ybO0S228qJ zSZUxaX3^k76?oN8VI%gS+|z^PAlua=qug;FD2}JJz^umJ;#^hSHckWKFk$cC<=2x7 zXLmdlg@0x+3mPicfKZBWc zR8+U1AUx8430fD+-><0^er^WkMH)zQ4ZH(zE4WY6K$SMsV0G;dT@9+-D6xs zQ}z~T2R@2uH_X-_I9PUnXaB8p zn;k?=2uL)_Zw$H$#z5g4V4mMD@WUY8>IrA!XJK9VKeGpg&Fl~Qu8+I2QGZK46OUTt zIg&ez=m|MVxWi6)gbYhG5y=JE#0^OjCdNSl^5dsb;dnVXk#-PLyhshv(ov!e>TFb|37@J-VlNID5K#<;(p zbhMATt>Z$?mldZA;jZtLf~PaeEb=y16WWoo8ASB_pWe~ee=GHF2=Dx&SQ(F=+(fKL0{;0SFX~ z5Lf1k!uj4MPDB4oA*?yRvYl`d)X>;X1I`i!D6L0yklq>t5@QL>faC_H$5}g??H0PK z!rn(JEt`mu3-AMc<@qAL3#;D>c(#6Zjnj6}BU>DqEc@Or+3G_U;PQ*dZ$iKYfdfmM zN#=%i*BdD>H@}0XL5MKJ5IEWx(5P|B6mpipS?<;u2w6x&)r_in=MYRrFjUkM23FfD z6$P5&dg-DVNOU89A0%6P#3qOp(vO2N3~94L=U=~EC(kV+mTq9>ypA&Tcn-!gT}5?x z?WOw)E#{kIcJ9i7%F)Hb`T-LXUF!ad^U>8=%A(1+s9zU4k?dJIYl@5an}EX!!d@q2 z>XHGa<~Oe1T^7o@rMD`bJp&g5D#5e^05ZtPWAQ00jBTIJdK7Qjl6W)2Y$R5dsT>kh zH8U~07BXi`?q21L9#q#CObg}fq#Qk-$eAe~r`a^ZLX1mf{BxpHD^1y9HL<&85U(q# z*B|(&_k2CS7E>MAqAXo-)yFPcwo6h7Ako>wPL=F-?sY^zGtlr`x}&l`20h#2)L?s=!*`3i9}3I zdidklnZNYUH!K|@edD?PSw@wI-TNW9G8+jxD(!lmSaOejIKKW3CX&@#Sviq(qYk*$ zqnQVh&N*BCHq%^2cyB<$h_9AAeERd@5Gm#k>1Yx_NgiP@5?eN%*_`kHr?ya0wdz&* zM}NLpAF$OZzFjpE2!^avc}Kx&$wm$`%+kiLQbk?d{hh!Rg$A_S1n{Gra}O5-x%ZDi zJ*`ZIPofY%S7Tp zE#cdiv2`a!s&KPYnm+&+IlL-B8fRUTfXX6aCar7(k@|(_WIlOGPus%ciY`ZcnCAUG2nMeJS!C-CvUb@~ z|4Cn?>upe{Tdq{x_r7vTCnip!Chd$W;JlwYzyjN=>0xE-8gbNsR ztqv;`=dbA{%~Uei;Z=)pmnT?z(}o-U<7-;34Xdwr5}!wCi}}&RelY(CAuf;2GCC#8 zY^J4Ji|Trz=gbaU&RBT)Fp7fXyL|#)?K`>Hx$ni5E}{C;0=20#CQ*1QV!i9H@AYqQ zB<~zlseJc+e1*wIXQL`#6d+5GqHj-0#&$?HG39AZ1Kjk*Mel|v+a1VwR)#+;I7ezk zb4q;jtj(@@n=yT$mF3NqzFxXXiwuW6B`{nn%YYrp@qIhF=a6n8?u=4>D=f@VWl6%?B^<#jC4imKYXZ$8o zW|MIdEmeU&XI%q@V9u9xMiY!n4u#J9Z=$^BTB-i5wS(%-a+sCQL^JzN+|fv{btiaY zV}o+Z8Zx<=fTXcYMu81< zvFc-z8`SOYUsmkZkeVb~c?JL)U`DiR76aBEkEJ0cYR6lD5B#-*>8g&i2T2rDd<}q;&%G-Q056v{5sMz4&u}Lp` zTBzIJK6s7&Rf@yDlGWg+)sJEBsn`NeVYaNG1}mXDF1UT}}wkl;^r@z0;#kB^t! zFTEb4)9at<2XSpv+7s8%*-~71G+NUsk9_ZHB!*|I!yUjgCp?F2*;MdmqYL!r>ZCY^ z$66>Hg_ypk(K&A4+|l;;qF&DK=7)~K5$+F2JJmL$%}F?PP<^WkH%iBV%Z+|ggNYes z3I2B*FlZC*Rwx3t*s$@!gv>?keUhaND`MXP%JE94o_{JB1M<> zs&E7Jyp{%tAZ0w5h&XDk#-2D%fz#)Ebu#EOTe;@|$ewox?lc(at8TLJLFcfk#15q0~Ig1)tO(Gs*qY`=QJC(b`T6hJimOK;u;G|R1$ovUJohzB&1UOs6cTx_?+$nqTQFzY6zp7T{(? zFdT@Vqf3tobq?r8?A`etO}em!B@k0G0lp^Lzw7qwrNb=Zy^=1gnXBz&hxK@ym;5|9 zuDB_GK71@0+nxgr-Y~3lD{M#aL@F7NJT^d?rVlI@JSz0Sr_qi+uk^&`=>|b^Oq?Z{ ztdE6&xSz zCU52M(6~9cYHNR$z$aISd0l@U6eMRBM>pG`zN&Zl>=N=*?^Sr*vWmQrG;j&|6q_mw zX&u1`m=ByhPyrZU)uhdHqCnP0hu&T@ci{fPkh_m4$Hyx1*nS9FA^^Tz1Fm(?T> z<(umqL9MD0^zrFOPGuf{RIRfx$b`ZaPl=}Slvk*+to~ObX_KMWfcji`w(kOEJOj)d zegeHzIJong#yYOywb7)1lDi#=%A4TwhuON3|J=hbS<&$ax`yA^E*N;~o_i{(s4dk9IIpO#9cJVkz8|`DX&*TgdC5QQMSIpOue&;k zO?x-~b@YcshzbGnq5TbDyg=}?@D+HcRpku?s}3o-(1JNWqot)xq08-Jo958i)(?Yf!p6b zDnVpHSPHs567&5fULmj1BW9u_2CJjB1X1pizmCi?c!(65d~&Q*<$^9j=9`NY+%5?| zJ7v>7MJemp)Kyo)4K_-FR;%f!r6u|nTWBm2?9-NHP)2`kPQt$Kb~?vrd9Rz#)>gU_ zgdISr3Vp1y0-)c(9>3wTLt@{b(8UHRO-md!2iPtZeBblSv`-_CZ5=QIpPzO8;meAj zr2@SM=Hi5J6jK+XHs)`U?IqxxJ|Hi61f2ya`Q}5x_{S$sCC4hi3%969K8Bg=Nu)vQ zM2ux{uU&vmF!B4qPo8oOhXoi>DDpCA)EJ?e_g$f8#*PA8@kf9n@{_`j!nzsf&Lx8S zzbwnodB+Lshr;_4Ny}7q0|Ts?2m;j+Zk43C{wST#%1f}Ry;;+tq$&HXT1VeyY{Kcb zW}2VrnXl=4w{Ph%d)p1?a)N>f3%NS+WZ8Le>AKq_%*ET@Ln~jwO>LMz`cSh6hVvbJ ztZ@FnT#{RDh&ndXBcBr-NB~DV*8}eBr)U;uP|4?g%1ndTJTM~-B!e)K9kPkycW`4} zpADJ2yx&YW$&CPrm+!$U06G#JpNVqa;$8ugUi&WP?6w9w>3_?(i&zsyS|Hvkc-xGx zd3#M=absdGq&u{_SB)RrlrdImfL8_UDLj9~9j6Ai59RAp3?Vb~p`AJnKIH`t=_;!E#2k+#NiB?_sHo=@++y*209|6C?C|idMnFNHt>EF zCt_QFw3Dn>M+OQQB-&noj`n8`xm+Fcvo!x!m_cEv-F|>klz#L!S4b_ytGmZ44M&w3 zrJBKu*O5YBRvPLD4xevgM`!r07wRJEVJ#PS%|o$DrR&9e=SC5s7Fesj3&M*!%5X}n z%Wx9N0$@C4a=(u!-~c}~YSLT#7m2Z3B)6LUj)fzR5;jC;J3xz)O#>N7C&KvVud}T@ z)vm6t0&%G6b|lQW<3Wb6uj3k!h7#s5P!+oks)xCm{!(I!t+RIph*8m6W}|Etgin#b zF$IhI7yv`Lsle?10bZqu!km$%FiPA@5k??y-b;53Qlj&r_q$yy(eA@Z?^H2V!@Y;L zs^JhzD@lxR>&SNiTW+{aY9RN800UbY%cWE!pk1n?bT2QdXkTAhWA6xtQsZI9J{x=m zW>p!r3^LnabAEMXHA2nN_K!)@9@(*gK z{A{EW;G9pwOU*ewRy2)Lo&lIV_8yaf)`N*zRQp=mY}HPUh;a*DL2}PHqh^ln#scV7 z3)R|nIO~Spkc&x?)0p{nKgn^r6W2yOLjdc+#xGdC?MhCGI?_|`lh81H=;8}5-Ah%; z7cbGab*!T)Pt?FgGl1_;fIgzDb9Mg0HlLXA58Z41pU_x1M?a2e>;>L(K1Z1c07I3z zXA(oTO)c(WTf12lkCnzoIbJ67!q7Wt8q&rHSw&H~Rzm5H7_XNvoP7>*>L*pFB55l_ z_{`mfQc2#^_*-bev?B%Fo24BGXNLcJTq*9e6K-YeO`1$n;l5475xZX0>qDKBr)w-*9mi=Op#kBdpnGu&RBS!d;nt;elaP}D0N(z89DR3Oljr)r=htDaBXy!6 zp(zEg-R5J6hQ$IQe;C&sw@#9>_`}q zunCX_*?IfBIsf|k2;|B0+~c~h`?|Zs*e7lnsBcIr{?=CSp_Gqz#n;saqpblUCfhAO0TjbG?&D&ao9JG zj6~^WV^4}U>r%7;=BwD>03cqc@~jHAlpiuMSLmg<4_epp^WZg?3)ek}x@Ou}G{w5g z{cQ)sn7pWUs+a6k2Tg3=%9>fQFe@z)104S($RW}G3ScvnV^!r)XLHAClK*K;V+XoD z#0NR~MdR$3ysKAurQ!WWqw#8<+|D>@SZ#wheoJ|wg#NfqD*??g$IXMMg9)=u)}v?J zw{QI8;E8NpM1{ZXFdXbx#dUeX!-NbwpxZ)>oXqLreZ#v#_=e^upU4ai9f=C}`c{PE zsYsuP&$+wLdyDXKm^_@aKp-S_9bIl(k-+`e~Sfc#C=%Zs( zyqKrGM8$n%^CUt7{4QGE6&gv7X~L99(rqiMC#IPX<5;ugg=YP9Ap5pqU!J4`+VBBU zolM>T#o-m_% zzc(-S=icn`Xjtd}F`EUR^1)bZ)bGT_LnlM%7l+LRp-{-DrQv*EUO5L~*U|zazqwv` zF4(Q+$^gc2)UZW12>$`rm#6J|sn!v7iF)sv3hdPV0fRHf!oUN=(FocFcx z{}^Hs>BmuIbIXCc)zVbek#fw!ZLlX2WCz<@V=37>#44*Y!TgYg0 zK+m*o;5D23#Gh<7(1`h7qh`q$)S$|rn5`(&^Q}BHzcu68)y(|IC69NQyj@4uyO!hC zlmKxltnn5Jr%wd~XX5Ok$w0UlyTv)^+Q$Z|Hgtne$CdOQHzQe;%3kSyEq*f3Q1+_s z5q12lQ^gVJS73#f%)aQDMZpHgk5kg}Gf4l(dT#&s}2((2U1o?iDRaXEP6Y zg0`TgXx_k6b=8^ujr?W746=PLO*9ZDJ*hZDtPuQi-(pLrRKE=P(2(&w$g zOVe#+9LNC%(ac13a)gJaVtX^J=y^nrPS?4M;bZzD#3;%OMqX>nhlAsyQQBn~KNr7Dk31I&t6 zkR-!Ua^Ggw3-72u78fmOXuLYLIq<-Ob-vP8V_Vrx*2Rj-q*YztClp2F>!o5M$|5OtxyF(S^_g4cJB zKd22}n7mu`-OV8Uh>N@46JiX!7)Ay%#P>6ayeVrNA8Z@}WO1Fb$l4G!NS{a4 zl0SR)>*J1M?SNtD5$Ip+#uSFMM}Y^{3Rz{N#rJ*tr5l^`mjv~&gOyPG@rKzr+0U@0 z5skU+yoZ8GTy*)V4+!a=q;@mwZ?t>DbVA)YK7^+vg%et@u<_Agcd z+QI=hiLnHSrASDygemIpJ|lxZyPM9ubo@z&+ovY2Z=TpvbKl{9c#jH`NQPE~;krTTq|rhHJgVffz~s+c`@#gJ)3e9%X*bE*Q?VaZt{vcV8t;Du(0hmMl< zvBkGW@NdoCM!&2(kojUrOWcFX$7S^UsIWM3e<$O4>BXxq&}rS(z5j z+(@rT2wKAsOKgL?C|9qJKNtlRr+eP=I=WXg6aK*gpzMLCC26q2kDMg$$#5vdg|9Y?<&r(IZ;^_iw1FDmN@t!Voh z#X^z0@t#sTitB!;!@m-g9ugd`_D}K$N*3uS7p)oJ=)dMQ+s9 zFX`-+^}hnwxQ)#scDwRJ`!jaSFUghxP(e> zKuqx%Z$>LPHXa%{>#sx&woZSe+sio221nYdxWq{`###nc4Yf`0<(_L+-AEZS&VB?d zsdVC^;8ZSqP>(OPBRqTy?ELluhtx2u>Y%*oP0&gp4o1>H%ZyoEs?0>??5L_9X^B2n^myr#^GQ~gAA&^>k`LV#_7P=RNdwL!sDNBB}phe4DUxDCxxXTBjO zJDo?#yZd)9X{a&mh~cN_$9$}3d$^l|f!i06~%bqy(>`Y4(xggz8C5CgZ@i=ZlnsCvU!1E4QdEZ;;!02>z{k<=Z~8(m!ZORzH$3}TngtH{oHT$g5Er14vj)%@z z>{e#q^$ZrrR}>zQczBjGW>}cL?4a9^jvsy=cP%Qi!Pc)`IeH++qG-S9obo~?VHi49 z-k?@8RF>g|a~BlP@}~c|;mndbgaRdYoK_&efV#Jl)viP-qB^=j{ag~cp0>Mp(TufF zI3-5kGmQL2MDNG(+lVdu1JfUTZjRvgQq#DHqalpo9Mpcyd-ewxw=NOWl*nlLL=EA; z^B~(2V&mCD&1J%|WyRWb(sxGvCi=fVt2zY&0Nv(=B0CY9bS;G4`ZJseKHQqH2?s7Ki$eaL^y%@~R4YjX03``hx*3`}Q{`#CI)v6?aQGRvY2 z0=h2;@&r8th3K%+)x{320HDxAJI0j ziF!pM8q122=2Cyj`YVyI>5^krNv(Q!Ju=sa+@meG9^xO-WJ#Gb?fMe)`(I}r z>Dj6_i_kAsSQ|C>(yJ7x4ZzZNQO)gp>N6r^mH3WLJSUkuxO{e8V^SPqdexB;ZyyU~ z2fjLNNl8vJjfrQyw&nf0UsN#zB++Y@o~@F{AhF*Hf}KEXo0CXEVzT+x~BB&a7bX$~fH$29K;&^NH=NLc*g@}s4XlAVlpR;+Jb<8o7 z!@E*a+2a7n+~m;#&1#w2O=B%Xj=WAK-VOX#6jwh3>9e(I68(DK;3YO|J;;m1%=3Du zMGO3h=qG)9y8rH)Olv#9zsu$uyg2*}^fP)Jk+s|a%xN)i*_1B+UPKbR1bOQf5~-@* z?t%Xm663AVxbl31ODRW2Fl;{nX)UPVV=2QdV`F7asjs|LN2J$AY6Uw)u=I5i`qyx_ zuN>1bgc;%8HMD_H?ZgjUPh{yWMQeR2i48qxE*(B8AnY5LSH<#$2d%?t`^0=qaF!WI zzUkHmp!G9ozj%=Bb2XPm4QU9aD*|id4PUM)k~BnnxSH(NEqd*eS|lLuwe zrCuC3>-+ljdh3Yhj^Lxe51V* z|7l~k$s7J=T2x1bS?HIz*}_maHTC5TZ{`58gZCN!B5S1q8$aimJUINl9HVQl>%sRn zLxu8;&1OG6@&0)WAt%A;L^zi(x6{=auegql{c%T~5XX#2J0hENKG&J*Br? zvM!`-QxwxgwvriYBC?@)_XwxE>?}w*!Vm+v9{d}~7qn^Ilbk91^uFkt@kyOduK23@ z{J0oUalO%traJ2_Dp=FyC}%0=hoY1<0sh?BN^bBv~ z^puH816oy8Ir=QBp|lt|*_{LbghTxV8Mod~cdKW9Mkhyxm%qK#k>h;0JoNl4$M}zi zj1UUQZABdsXQ*Q(&->ue4d+H`32O(ZH{E0kow)&WV5hcvi9~E%qEzpohDO)1vM{hE z$Uz7%Fbx#7(k*YESLmYd-C%`1`Gsrp%~Z|JfMVTN-^!84vxbZeoHk0N=V>RsDLM<@ zYNqgf+1>#kqaRk2x`h6DT`XqS4_j50%GmumMgcP*3G>Cip)<%O%+TX33jkIpjN^Ga zK2M+CDR4fUJWsdb5HYOC!>=@Wt26hHoydSK<`YPoIMw>*d!sj-*xX)(&TW;AC z<2?wd3cT#eLZB*aRA?T={4&XE>@kGg+d0vH%|zmz_z1Nei~W3fcefPh+O~C=3OUHR zu#vtssuh}nJN@$YZ?m?;J1X1%PW(XJbP%ZyB>(2@V!?p#qSR}`_<&sU;|`vpb9-EQ z!YJ-@IJuRhZgTT7d`(sNj!G63NpNrN4)P}l$={rA>Up#|_Alr4DkHN+b0>SM@<8gL z?17J3)>J9->SjLgQj!0eP85_h*OjxK8ceab#}x}+CTR3{9u<5Q3<+eGuz=xw=mh1l8FcexMYtOnSB;m0c>SJ_@*JIYvZ zL|@Zf=b#LtdJf6bROmlzQlO$4pNj=2yaak8!Ot5%60&%M&) zHX;RRSrZGL&wL?e^&ojhgvK^k)cO+^_*PYCIcAe2pe`px!j6xzhJZ(-2Z@&mLB4hP z{rqn;r_D$fvUbKNqr$5EkeR*`E?BK;tDIUTGN2Fa$sU_RAzhZx*iPazFqgha(owSVj zZy0k#UUX_+H0T&Pp@{({;*GlYp zpGP4ij$(1{TXR3$rxds;q?>zLecQhKKmGh>F@BMrw*%dR#SaBrY|z{hJJo$DIvMZL z32g8kav^2-QcnUY`%|*xXnmNQOfnKWh^M4j*U54Bc;nng2r>5ApKvRtP_xcOWQ{+i zW16(>0g*AsQw)O%Uiz*nTW6Q&8t~z4>3)GWq#elx80iQNUSXUli!3!P%FB2C^hapI zAB3*3H8yB>{rd-NlES8^f`=N-GbfFE|5@g{=rAwc_9_!|T#vnT6&*k;e&AH&<0hgX z@NB(Q9{4_g;y_oViq0RYbklaPM<@l8sDtcjx+?>7Z{aMbi0r1c+rAVDt>w>8qa8|) z4~6ZHCfF5(m^YXv15^#_ZH1koR;lgjP9Kp7SPr(~&pGqsdEaEqCj0T?lh@IQFoRSM z88%2>B3s+Ohw+_b-TIT=hEN9;XwlLJqaW7s^s(3r&uQ3E?53zv5+{9tB*57NOu85u z1_cSbn&$OsYNBud++iSm2K2Y82K+^;J}$xdJUka6AzV`@u!4f!q#-X9j4x7`gfpAY{Jm7lwjP?uW)_*os@r0|5GC;9Y};DW$yy3f z3fzmm2~Y&O-dbI0D6cYtw~|A|!h#&z-{Znh$eJK=i++MF+`%$UNpTeZ6x!cmzoo3m z^SvG~v_*iuLOxG%+yU!LUutd+kZLnd)Cl(T_sm;D8`h?_;C=y$XFZ(9;`sJ7G1=~i zrCFI^nyB*P-Cc;={v$(ul5+EVe=VZu9%o;;6MVYy{PQ^{>@Cfsdmh~}2OW^A5&C)w zGi!&8Z8(OE?Rnm6%#1^I0w16k+ zDu#Kdv%P0J#%Adkm=`1V)re}7pDj{LrjZrm)cVL&k63+1sM|a-KX6*Go~{s9O9aya6BR5NdD^P?$oRac^8@^Uz4%nb=*6{j6v{yf#aib|3CD{$QZ$! z8~U$?Z3@Q8{pwWOe|qTMlnEol{Q-WTaq?y{dj#LV5Qh!u<+x*1J`b1?*8Ow=%AOU8 za^8k{6woef5{ld-F{(p#ZO>BzqD9v8p9cR~rZWf5dk(PO#F4+9>j;-r^Zpv;dDvI) z2Na5efu%vf4298w$C~o0H!>75Qzc4l@2Nl!`Vp;S75X`AW6SVkJiRbWlCzG!;8>g#(Z+! zw>k4jY*fU-qOiYx>EFlC5-TIqX=I6W>sbzuby+C$B-~YJnaSgCIiJfNf*x!-O*b2} z!Q!fj$1xhXAw2X~vUl`eFNgVT<)u_(K*W34FA~!0UPYOCbRu2P7=dxVh&JeRWV-<{ zup!!}h(Av16pcTrV_BC{U){7`(ejf?LZSV}BG5@%)$NW}wi-oGOw<4(`g~hfl}=r_ zLKol+%0!;K&(4=uG=^(tYmeqx9=&NPYaEQhBo^5hI7@-7z3z}vr_hEvM~_nPV+Vxl zq|0doZd}E})HpgyEN_#E8h-B|8g9w+QiViunp2I5lXLqsFPthx`zpF{b_)sk-eIl1 z;>`OkB%6(kPb9VvUfFHmcsKaIlVr*tULe2#fz3Na7pqH|t$Kn1V7E#VeogiDHP7>> zg_ZNgfZBs@-7fMy71NY@-wL)Tc*3>OSwIW!*6VH3)1-50zkqe#8Tc0Z2#YEH^C(6o zA;0o|Lo;{4*St1en7LF|=q)_bplLQ4uKA00Rx6R~JIIn9>_b3HGg0C9iEVQoA_3pbuS>+*#Xb5}RSoz}T6eS$ z>i}!(@UaxPiPo(oKM(Sc#N8PIj1gDMsAP9DJ;%#obDhxTvnF&~uXAXDTfWBoB-)VJ zPOiuUDU8rpbN+8cvW~1Bwbke#r_L5W3h42B0SavF?_viJRJY8ko1NF>5K$J z5atdY8~yrlnlDRk%%4NQ?vOL@7duC<$r(xd4jIA9E^){~o;Kv67Hjn|k^LTv>Bt|y z^QQB4-C#|?S<%{0ff$uPH=)#~Vc4N6zR{0+D;MYoAsq%x$Z}O6=Pzy6d4w<0BZI|3 zC*^BOMydark$a40w7KdDi7r0#`0*D_akcAS1`lro@&6a~xx;NB#p?&e1vQ@2bCoF_ zfSQ%eBO#w~7*do_c{25oagLqfFfBUIL|tbMwYmM?Px3F7p@pQxg0CcP+dJQkN|}c@ zzl>dU0V1pMML8p$yRmn!oNDc#w3OB&k{bm&xW2^aQLLsV_T6w?F?P-=io+iwwvo0e zccZ(aS^e0H-L~`GMp*bs9UBM~)r)SUJ7l6nZa0h#KImc3nale2?SII&G1re0hV?ou zk+`F^)VEQ#v65$=zh)lBUF4v8QJ=T40iR?A0#aWn#tEh;RRT(|Dk;?hcr1s+xR%{5PwBt z%J`|Si5((SXI!*{?)bxKie9AAcD+!*t&;KYg#$sJt~@T-A9w9LbUdvb^UxWQIcg;y zvY%rb4lpbH82$TO8AHOB-S$)5Et>5)^$r6U^TJm68Grsjtyc7namy>X}-an`L_YN~pi`icGS2lno} zk#`Dyo2OmduJ$>oJv)Ilr8|JNaQg$7uvzAw)-T?=Qy`PAK!;)lZ;^W>6JzdvQCUl_ zn=w8J*J6>4liJxKl1DU(-ktUx+NF`_QTjUSp#d;9KMc)t&s&;_s%#{@-$W(HnX-(A zwDg{sx`}K(Te}>p@Ky(X?fxt2e{b=$ z-Z7w*^|mI> zz^#jWF@U=8#&07^e&~55$M_n~ef$+dKWbdR{qHz;{W-h4Q)xxKN85wFzkf@aKWiwO#rX~VeCCny)Lz2BBup4u z(7T~i+7=s)l$LLXN?`(z?y4bcF9gslF^28PI$PWYV=p7|TeO{p@=T0?KmJ`fc|ByN zm-{-V3K{NH;d;%>h%wlYBPo;US)@#|ycN7)uAiNfQACUF z6l^5=-#?JI(+|uJa#{&C-s~r>4h62WM&fc1Q4_6n-{}5nKfcTvPb6a*x z@sav`NFiwvxQ3y1B6qp9!LxXzH@uZGd^Y$1@5X4P8W}3yB=yw?rS5n%Ga~<{;jKNl zRWOD`{%7VyLq~F)w!)s~wmXaz_X7A+XT5_hK#v`aSNSL$R9Zx8WMQ=ZyPz0jB+G*MF9s(VwnRpfjQ(>dZcpmn>~wJfL>W z0%B0e^^N{}kP8ME$#}r9Cm1O`5*l3OmzjS;;efM7tzzy7n4bg4TB@Yxd^6oWk%^Qs z?u)aIMn_QiFI|{#gq5J~x28WXb@rjwLsbaN3Yj;#kR$`Mp(^G(z0~sFV9V$%u~$r} zlP`4RcNO|snfsXb`YhXD&TB|=aqz0`F7xL*1b}z4g$f7mEyhK)q`rCLv0oG}Y?jqj zwJK-hgN7U4$x^|yeelUJt0Y;wIzX}pwAOqb8yA=uAglI&9nESCEXqrm9VzYFA>bT( zF|87qUR+04NkP}Yg6GKHNxLR+_9=)?FV2b1kG`ROXe_3}kK4+21RNuM7#u3N;a%`2 zJ8EmRxzl~BKlpV4Hiz6k_7y3P=p`zK{4z_-o=w7iVK~}3UZTiyl3Xb^@Zcwy!&HIw zW{b1OD?f@zmZqT+5Qb9YIynsrgf?z z*0~apn7u@MIkw4lz2>1YQ&s`mA7qb+9WmA!FxIU!s$Rm`M-4clSc_2YPKnfy{8g_5921 z+3`91)S%hEB3bL{j>}~aCe_@4lUg-wowMy_nZvAThkH4%Ywt>Dbs17c;aiT27|{e~ zt>{3_Jml%-u6ooJ$G-L=+L{CT$8HJ$?^@8MUJr5twCDq=p^-V$===+Q6DOWDf>KJ&&ndtUi znhepkLiSzW={05tawiaVu5ygW6Zz9)RBlRUh@_Q*Z5BfR%aewbH7iW zhDbOslNxk1AS*jC;nen^3XED}Gna=D5SVa#ko%ci{t)O@=*7Jnx8`n)Kqr5$8GY;u5aszv^!t(fB?s%uOb-vpw zQUAWPGn-tgkJEk2QRe4ixWV+D{_~-1K3Qm8?~t`olUdjw>_||>fl{@{I8yj<0z}z0L0)8H z3{(p(a+vr8okA zuBI!3@s%IN=(Ns}xE3SpQAJJRJJ)qnx|BSTx{q)4yJ3pLe)`V&tM!{&9 zw-Hinzhed4m>M>YeE11F2w-Ej-1E~IYqP6`@a&b+vywgYojgRbee+O{z%osbR0CUBd z>$-lS7k}w^_dc*M!)czlZGE&DG+QM560>=VEPEW#mNS&W-$!`eRZgy+MD*C3bzqk{ zTRr0C{`TQn%J7l2w}ST-@>O|3A5|@C3jk#3N3{u)n%$dlGfJj+W7b}a?hXwSP^-T* z3E8w4q`LlD_Q{?}fwGAbsErUz!%awIKt-1W72R24m+shQ@P@@>t{TUI$nR(5~m_>0WE`ms1E^p*6Ag*jJIi?OGpQ7_WQ8V6(X zJn}0UdgiYlOHySG?GPE0ok@`N_td?c+YlpyY6swYr;+&_$gDweDS@YOgYG!pJCVkU zZ6~9~m#=oHznNZ%;*cA9}^5$B1aN6|K=GPc&jWK~~w+Gyd4`a}8ybCv(shwkZ@2&v34 zeZe)n0AzCUr0 z=q^oWE~Qhm7rR^&(@wTUTPP^gTJ0cc4LbYm4dJ6=P(Ry^z0*3<^3_ylp=`9tG1nn| zy#1D{AM^Je$66FFv1>pgKFVToq`c@?wOCe8Tryj+ntJ5#TYuX}Sabk&-ZgyZS32e&iomi}lL zcxueDf{bFM`>3AziT9h`w(d~-(8JQU>Yn}lMb-=&W6;TNCRitOLUSo_JBzBS8Ahsc zk^I8cqUgFYBdE|Hd8sFUA{rV%ktSA*ox{B* zP4T9$2d|}z2}+~TpjynH#D%waBfn*XdaliS|5bBy>75(2`I}~;ngvGD{pkF}pzs5TXG-Vb>L;QqRTNGh3 zE>J@z;Lu!lAa!IDO-z^A3||5Jb(5!I2$_XfbH#{gEVmW(C{PZ8wYNXkQ}I5>5_R~^6(ac>y9Yj zE|=wR$pbg06j~;+1bM~KCm5xp>T+?lMe;Vm^9Q-dgBU^EJ?LT;Jz6MH2#l|Rr5 zbk*XM>3wZ~ooo!Vw98NW6!ZqWiT0nqZHe!@LIU@}r}FB(l%&26-ED+!Tkf;`pg;a_F#DR zIa_X}hnJic1s-Mv8z*%Q#TjpEmQsd2->~p#Np+&2Xc~}ePCV4NiOcj z^=fg>wRyn{Q%^T5>jJ%cQHI2jF`uFKKu17rdLprU$qti*6@V`VS9mzb)r zM&XGuQMRG`ev{+l>f`2T6U6*2S7My;vIk2bE^ik77VYfL)mv%M4U3IQnW>R10*<^xmex+fm zufr>kgKfiAhbEI22I|}!)xXTF3!qD9{SZUU(xzmq<$ziOpXV|U)AGWwugt2-YY=PD6laC&$>ZO^j$yUYfLoEe+Xjy;|R70C_LB*0cH`QG@ zo_3HoVp>sJqqGg3yBr1Y@J5}FW_nGv!+#B*6-B+3>fIV@a!KbsK(k}Xpkz*f{e+9> z{##y#7allKzv)Skp1&8wR3VD)4w-#@&ut@yLYhnW)H|(adafs*wY&i8GEwTr-?hZo z!RoB5H=4H(81$}W?xS(v-)GWdnD-av{7zs0{2nVRzo2lxA*WAP&x<#{?@UJCu zYo42`s@Red2m07>oHi3Mgl^)$!I#DN&lZpLIJZ(~&7|c({r}jaXB+5sy92Loa@ZK3 zcjv`IuYoZ!)!TSF!YIAzZ+@30HpidpxXd_SYn00S*zqqIkmFyxCay5DawHZ9(p^lB zD>ytJj8==KCqP*G7a^%xKLC|=WE^}r^f0n0l9?Jw3$j8Xp+uh5)>|;!R>g}urM1tF z9Fepg!0shzDLx@N%O9U;s?WOnqUyfOQPSAEbFbKDQ#Yat-_|@x#TsZWCQm}FjR(k2 zY_7pQOY1G(t}X+~$-LJETY$hKSW>_5}_ud@qz37kzxLN@rn{UVx5K4m&iOrrRlq**n2QHXyuGkyH-Ci(>P0IAy~ zw|+LoE1*r34A}S#xxdQ`O|?ed*mz9_SZuhA!`Q6U%)?BK5NIcmmSts>Xz6^BpNZE``XPy^&1-a%? zg04rZj^sjPrR;w}J;iL=eE-l$3N=JH#Fy!lS`0ib#m@pp?%3$)+<+^*fpvpgvV0HP%lx3UsN;=LZ_)7ZP-g_t zR4Udh5vkBNPQB(d+R4_x85!cm;ctsMvH1`PzdHU9rqDEas4?&5yx;6S`KvXN`Y+Ai z6<-wt{)`T?kV`RwIjoF?|Jv{`@KK7CQp@!DV{n+)x$p#p5eo-WBZK5CN4W893W@M2 z`g{gJ&w0%qcP~7C&vK}3y&yx@Ri#9+hQ@`B*XWT`>DUB=jrfO4RY~tF8EQ(jAz}*q zRk#FxZ(*~eU3q>R`Xr~t@)b+j>ADz;V}yI+m$#`hV~utLZAxe0*|3ujq`~&iw8i(G zm*e%v+sP&PM|%DOWxWPmcB3w@#1+i$pcCu2G$KW@j#;y3stF=>#(&5SuyP$rBI&InCELQPrwp`XWI>o9bP+?aiCSrlh#b|D8R*_ z?a|yB8FCs?u@98LART2*oq~{2H_K8qqndn<%d@k_QV#)#kRO*?@3@s4)X(c9P+i{o~3k%OD zJIak?*jnIxOVG^%uv^c`ix!3Gu{!6awWAM5<>Um5|HtW|TL%jx>+`QJiTe$%gIp9qGaW)XMa5wtD{Cj1P+8^72}OCQTc&n3pkbY-KGz0%Ob=*SZ&N zVI%w@q`Oid(QzDWw5OBjZj5vWc_2uvr|3@#>}dj7P^f zr_+YX{US{yPyWxc@>7Ownmbm{qha*g05>K`^Rk`1v@`-+WYbKw1iaQ5k4X4lv<`!a zo!0Bhq{p=RXuAS!*Ij!kM(+MBp<8x|n<}@8lpB+IeOjNX652Hxsbqw_Mw6r`&!$LB z@Ifdvd1>-C!yW%bM5+Dvhjl?hsMH@Q|Rp zM4B6!3-gp$-U)RkjwEme*)!NM^sM2ZWy(fqw(_qT+`u1_I*WCBFR)!w5Tt4;<`II1 zlg-{LB&6g`d_iKXjXq{iIiscU@ip63&&1eWXHdh9zNnfsyGJ@7`Q!*5CJOibR1b0Y zAoD$`;gn~24h7>Dky_NjPZRGi^G$d`@-i<|l7+dCJ%1&qkA83Q{zm)--DleyIP>vk zIdKj@IIUQfmp&cpZ2gLaG?(r3sr9z{9TEGOJi;06UzT_k4hNH`P2;8b=||D;Z{yngYLe(QU6X|+$gG}j|%uOQL>)fx#TRI z1|>6gZ!}B-^tk!ahv*DmAJItBMaCO!J|)#Uu{4>Q+A~S&n~FAl@=iPt)e}?NKG`0J z$;5*T?9})#-6UO23T2qfs)BLl7;~Qgf6(19V&&MD(mu|;XO)0+gi=g?|0CL02R)^G zVwH52<}wJjSb}S&&y>&$s0-|&s<74gpxGI3ZK?FNj?@(|-5&Cdu~>l}Mw)ZU%C0*9 zPmJ5M2A}=I+xs|kZuP!5v9WOf7jkTG0p2w zIW%s}>Q>YJkg9Sep#c|fI(chxXU+rcT;R6~^4^sq?WFNNtm)PtKqT8?qlF3DwWopD zQ34vz5#|m}>5Tr}RQ%0!hCx}hM?)A=*zyX2{JQnW$KLFBGZD3}wL~YaIYKFEDvz$4#z2yZj;FUcYN9U8R-+&4hl3b4cSFm?9uSOsGpb!8C zE5?K(q>FQQ)b=N3yZ-9FXd?EKVtbM?-5_UEPCb>AH+?W7TN)mpIiV6B^(|*ub}XqQZV=gT zKeP2euHbe3sjw9rC!f^Ro+%#F#C|f~AUK*4X5;p3FR2EjPA^zO;Ss(>3%yfV^{0GM z?x-SIQ`0|hw_jTnbTQ^Yjxl?r&ViWn0}^3b$)A9Pv7emIIrUxfe$hI&JP#Pi;o%C# z(R#=I;Lz7m{?b02QF^NQi*l_<;t;1(uXbv#!8dw=wa|aE?7GDY1N##v-k4}ylcGA) ze?Ca{j4`YsY-iU;JeP+3nBkj#EQXo7gC+ZVfT^}mpyX@uoL5FSUj=PO7j0zkTR8eM z!l(8z&*D;PH*I+?Y;KeAP!KXeW#B^mEb{RtBnqG-m*HXisD89>{$T=&Dl^ z?&$_&)QK;u8S0A8M)MlDCu7}{lMBuU%Y$7xEdxJMf76AhGaCsj2i$Sei)q~Vn#s`t z{@49e2!>;#XMYoL2z_L&0!!Xy+%Blq~j6FA=&w&JuqKi6jdHhQL>Fiktci)?TE&hV{5tTEJ8ebdEZk7$Y zu17odJBTd#o?dX3Ogjm+2Eth!O z?s43o4fVI?M*Y_J)hzWI{9Z;lLw~Q=A-;GF)L(L|(*XP@N zh@3a_{pNuE2e%R)pAjz9>28F)KHfyU8xi8f*M1Jea*z_>l}6(^$Hv;MU2j>D5q6?T<*|IF|UtN4mWPq`CpRUYTN_i#>z6$YcB_nD%q z2i@w_*?zT+TY&r`tDn~|jL1{@J^{lJkk#JtaEZz8D0{kR%JqPp&s_4e%1NH(0b(B- zC4w}ZNSbUn3RF)KRTsB#`5jeFpPIv1^ZbzKC(VQO5@$j&=?ZFAoAMrez^`LT6aC+W=tnmV`c z;r8~n)&b*86(!e^tB6!(P=@5Q6cG`lqDGlgi->@bDj-wf^cDpbAr%TKAf$+hh!B|t zLQ)x|6fw*(VF(E`1d;$5NODfU&HMYi6-dr=_OsX8Yp=Cn-STAx>;;(GiqlhbfqFn+ zw4F*g-J|EzVJhGrDQfW==ypc)VOCOPe*aca!eD|@eRo5Amw@}m4qm9OwOt%yF z*&b%t8~MN1E#YI*^o=D1zl%Ft+$nme)#&YKmShr>ubVUIlRV_X5! z^i0G{j@$+1B8oXZ2EV50&GP(MvAdxhxiQu4>O;knm)FhOi1TTJ1l98G#rs>sj8|L< zm~TEnsY~T#ugZ*N<_|>#cQ>vdY*wA!w-23u=J&@8(Du|26D5aCls$qqc|D1`eG$S8BO_6g2#CWxD)bxqYJ#< zT_BPE1ISi5x%h#wWhtao`}EtM7_OPpE_pleaO7Un+3c=;p0V!fcP~?h%a}Sgxb4Y>R}zaMf)qCF^W!npl`kzQT~D55lYlJ zkIw@t)ET1KQa(J#5Xw3>PjklZe6%kPe2T<_R;oS`_Ld8cPcpgT2goDaJkjcW?BwO~ zQnhF%CaN6Olkeb#udXO%56(?N^ayFyByz19920AvGh)@x(K?MWNui^T0imorAb=2nE((QN@(`I54U!64N ztuSXCe8K~ti}D1Gcl}H&>q|6emMF$$HJleXs9dP)ZqCP4Nn~nd>RXNs{d{I})#5So z=gRGe$_5t7YjmfD>y|7W+%9rlW0)0$A0(WeNK+1Vt)>zCSxxZ+bv4VMb2YHGx8j&G z@i^@F^g^p~aE5rf%ZFbv=;T}j*G|xP`{CV{v1*{mByfy1sSQWd^+ObrL)n;vSW)!OxvU81G5Bd!S#~wy5^5p zcJ7c4U8-QtcU4tn+s>xP`UcSxgg1(D+V6)*s0GW~aLr}d$hcuiH--|6y)};0}pZ9sAwyvKl?+@BmH6-#n)N;_avkxo_@imWEppErQ3JJb9?|ct-qzAIOL3IH z2Zd+|KEp(1#@A{(0|HM46DR00pOTp-;%5B`mZtx#!t+gIV98ZXHoM*dD|^d&Xl&gF zN(AKQ5HR9p41!~t+Lz$?o!n`*`c@|^GUZ(&Xy zM#p1G#cv5;4Nb#cpbIyERU8y@Pe#7IR364VdBo9Ye^1kl!;td0Ey-xe!Ox(A5#sW~ z18t)Y7lT!Z(1rm^P9O*$sn`XE_yVqwwz0hWo7PR+jPwZOchCt|o=BWy= z>l9=lpI;pV+I&qz_L&wYQXv}xy;&5tcV=M|!6@2Q`KgQX*yk=(J66ZV)sc z-Xtwoy#ok(8h84D8?$9#$@o7XCw@JbQv5ohKVE zn!C74!o8mDfvrPbuywWquH@<~_m&b(csuB%(Et-&rPSD%Z-_>X=b_ACC3s;U^W|wq?jhvf(xcGn=!kxaooS=UV6h%Ap~hS6 zh&~GrNWFG;I^s;3z85at3R1G&357K!z8`K{$8L*boEG08a1iL9m$6Fp)Mw5kI3wD| zRLp+wTX{ZzPNLKG@xy3^;bMD-3w=AQYr0t$FS&h@nfC~uDMSVT!;jzgOgH|DGVXoL zy~;ADlK=W!6D>YYET_Q;zbCEN;rURYkfAb9*opP^j-Vqg{>!_fy80-}L%k0g_d=k- zzte6f2E+7SG<^gF%H>s5ZdpAU+l%2eKK_49)`r?3{dRAM#?6%syl6=I>6L@QFUhOo zGiS_?%8t>K7`QHNx-qfdlCza&(y8BwX6v%-sh)uSSia~eGyrcZmv`ung_&=PST%u~ zpMmfARB1H>i+KURVRffG@iI2l5j;m@9ym4kyn23;e`vH^BM^&90io=4*(xn~3-3R2 zg#4NTXRf&iyZ(OU_SI~J`Y64uXB_MgsySBOpcL*#zgj?7Y5P&`a7kd}dJj#%q%T2o zY&;7+!oN_B=zawCR5axQ&7@#PXg^pf(+UWqupXKO8Ub(r;X#vg2`4n+(INi-eD)vo ztagZ027M68c5F!5mT^(_Q$k_y#wZSPasC6q5(b#;`@NLw^ftL@k0XZgjEgm5%056fs>CiIf)Chn<3LRZh5cw-7Ob{mX!zaCd*P|B+bQ*rMCw>S{UV||;I737 zyy~_anE=94vs$v^QHAJeD?G=02_(jcE+t-hha4_vN~n61bVMNRAquAax!1#pbns7L_+B;DT~Z-BvE@4NE4s`><-X_FOF*ApsRf|g$ds`Y&ABm7Tc zy$0dO{Z=Y&{zKXa(&8+BA;hVqRGrh=GsrlOc}p8BD&Gou)L2b z{!tUsxLZh%s+(isq&j)%Fq_X6tRAJKkxhYaJD094~ zKm)F-aMo}_DN;oMrIzweFox0)-RX#EPYqSE`+QkXg-q%Z2r8xS;^G?%yXT>eh^jXo zQG;2Kfpt@=qlqf$wKrAxpRVF-q($N!6_H6xvLxzX4iWu%aCx>EukL2qo$x7`dRVZR zO_?zhY1Ae_1^jp*COmV+)bX#rFlr2|zkfP0jk&?K$lDu+yd|PPGfAJsjPq}s%IGyz zGZ$FtF=|-|Ao`Wbo5ypl_4Abp9}wL*r&UAJ?P)c5YR$2a4?58QH~K!?P#*(W)BVT? zJoL9nx6j;VpL_3)!?t&|&sdS`K9a~2T9eb&1yfxykowVw7nnFCT*%USG?8J8WWK?k zh~D6-W`4^WrpG~f4RDVjo>hF$zbw4R{V`gULM;DKRn`v2&57x$YGXIU?%y&{~nDGk&{nB z4Zb?hr^u^EHb3QV*Kb9C+qb@jbKH)lWEef+`%>fDr%-p7+0dF7{>>WqNc*c|Um2Pz z!`Ym=C9cv@vNm%Wg20KmBr||l7f;j$?g*3Bj0R0Y+o#wq#X^U+_r3sQy2ZEb zc4IY$+|_p?ip`U?N%=YXqciTV1N^%~|LGjA&mk_UvoruLU$YXooyj@S9XiubU38^5 zaOs!;R@)$*nILN5e9J$`-XD(B@2YKPsXpM93ovuMJhhx&GUj=rHJ-A^2^Zn4H2a076 zsFstox8tZxuLn+WN7|J4LAfInobs%)qjiNoi64G}DYcRGHQdd1uHW>ril2)l(MztU zBeqX(jNzqo%aAH!0`Pcg5a+r*51yOcx9+Jr2$f$B{bYamy0;}#==SfNue*eHu! zMy;S`yL>tCnZLG08ysh0eFrG$TW5d6HnNlo_h(C6tqF%SB6C|lISCKZ`d$1Qh zlUz)>&N`a;Vz(d@ztPNhoBfO5b}jhoNd0EWOd_0ieT?bf;F6=|DKC8jLxvlrBdhJ# zl9v8;rN3>@PtFI2Jk={r0O-_sBjHwsYr*=j$N__?eEA~|X=U?8#WB{a+3^VG75&E< zl7=pEwRVDx>Kj>7Vt~$x5eRN4CH;RQ|E5JM%A1(}eD*A%1@jmhL?%~y`-_=IGdcfe z>w@FLQD%sD8*cW}>xk47Sts~#dXizc;SUFl5ecJUa!ukyft< z$%`&vG03obzwFuq0dkj8BkcvQhOrnP4ev1@k?1NBSQ8<{?F%XJ$_ za2s3rAT$5#r>AYASBu_f7#?y*PMo;j))7EdT@cYvMqIS%lea%dW{9&)biwP(f%8Mi z>(?ZlD^=C*bQTiEpK|B>YSYY%e0;9@8x{;8ha>^)OU@UWP0AY(YWpldT_*hrlc~vk z{2h{t$n{P?x?Usv`C~Vcw@g3T5*# zzlCnARuM|AYS2W3QTO_$Lf^0*B5mtF!9ovFNbEN@njcF*O-RtC`y-snMET!y3(aIk zEU>WY7rY{o`X#Khk`P|f(ACAepdhQNwIZl-Z7??ll-+m5hIyg!&o;*;1pKsoMs#RM+HM9UgUfs4`WDrQpgmfaCNQU!v|5taweK^UuzAyG`; zb-y1eyhd@`=)pgz{BP(?qM1{BVmqo2YmZRfl-X@8T4Hk2McCD5_!g$kra0_Gmk~pJQ#c_R;_S)VSb~!SM?zUy&t7BG*zMIUytFMpJT-S^D<@3F=dt3g`6nQs4+PaW|L; z=xq}L4n1TF*e&pr)3b=+X3`W5!$R_v1b2vFjzkk~`;4{THkADb__3LZVh_)^eLK7J zQZY}7&W8N@rJIsa_c<8U-J>*J?6Gr=EOhV>GSL}@xw;+9M`qj!Q4_hd#YDgML9kSc z5d&16kQOjL()b1u1?o5XZu<6jyFHI4cjPk7}y=n|@lVJy{c|ioODpm#08T+j09}GmRVf(a|T8x|=jXXe0tI zev4J9V~B1-#wRQCoKaq!g%MR*g(!|A>i)UQ8vR-BIV}9To=#v2GA6Y6L`%}=?Q7#k z=o&>Tc4FuNDD1M3v83iOZ<7kFt30y}yXqV;zXueI>HC8qLGM8^D`;nrMeCuQ<8X_Q zJ!S49Gn*wwytoCgAwf)eGh$%z&u4=u6Z_Hqh&9%Fn&XQ;k^Y8lJ^Ct}Si;LO%Dddv zjcugHS*4T9V^ZLgjJ#LF(jdGX7Z)RNo@`)^k%nt5M?dQaJ_{CpfGVz{*(!t!V=G%( zN!+mS5VP>6mXr6qeJv!S7k!8Wwj*#{aDcqJ$khbOb)q_UH*n&bwF`fBS5EDPVq%)E zV?h~z#@UtCq&rJ-L;RqQA1~e)Mp;*}1Q~Ixl^#xTGg798ob+Grx-PgdCE6H@%qH!2 z?70D0G!;eAqfuFs_qqGBB&@XpNY||`uZ_bXh?WTlp8Ab093Fih$*sdo>|j2RU^jtZA?;82+nhl;`F1K}N5f)j>p zG}EsHI$=HBtM})uV$y4ID`>7=3K!%{x4z}ADHd%e0t{&pzj3^L)%r!8V{>CQ&{GnS@5INZbby zrr))$3s9u$txhRl(JYEj5X+JZxC8n&Ui87IfD63tdJU}YWWG2(sCW=ptF5PW46oM;I z8rT>#3F-Gad)j?fHCzcf_e6nR3Y=GNgh;!?=RuPP!(foP|M6dkucq6W8ks**IrVH4 zEjNKY($FQYCav+0!GY0)tTa8=QKwQ@6b@Bnx9l*I-Sm*mjh{Lt6h3>;UTS-m=&my$I`KRX&4^O zGrN;HYQ3!`dpp8OAEKD)U-fBPh6l|tL+b~{#g#_9b)M5(xHl_%e9-}>zepc8%9Ouh zJ44Ke*EF$aA$afn-1B*e=NJ_UH!s=WC&ksMYF2E!Sg`htQ~if%(LKHWo}n|h8^NgQ zbg$@Nq&Ef&k(=VGZ&{0 zA^phQWuyT~sKr0DKt7uyn4+^u6GBce1k5Y&!rx_7V`s|m`jPeT1@#AxFpp>$`i*~R zwho&j-+(VO+(S)`4!veb7k5geQz|br3!GjE(9C}HB65dA(HQ#QmY?NG$oF?=eXQzK zKG^dMQF}L&^M7tmlxRlnM?6PE|M-?}$I9wMmnJA13F{*$690JOdiTgG;=3z3TjeVH zF!NC+H*U6=C~=bDR-G^raA!m`bC{__hD~pq(4VOgaM~g0p?4{5#QmO4K|HpHcA&l{ z>to_9S!k(j(Jwmxv7EPqKYch=6VpBZEfTOD^pH;Hd+hKdpi|l_lObjLwn1Z(_AV9M z$7V=c-r=`7NLcG>Czj(JcAY9&j4HHl3K1M|CxDRSmXM+i; ztk}cBfX@h2MI3wvS18{8?i;;Nw?6X4Os4r`GeWC*+TL0xc)n%igl0)}`-)+lR9EB( zpT#QbsbYyKr75R{RmFLlBBw0(vUsDqEaGAU4Ac2V|NEs7_kGBZuO#3062sjX*!Bfd zJY+Nt=?Z#labJMD=SrNqL#`-|jth$OU7P#|0F}zE7)|^RiNYA|}So zjk6xc9>zXyONi573TL^5qs4NTOW%KbsG&s^<&)=h-QYt2*W`iC4|4}wa83IwWF~4d zo(&jyJ6-LC2QHJJo%w_Kg7Hwyia3@{RQO$sLrR0S_!WbiYu(!+Q9^mjNfgNfb}s);tQbxlxh8`)D^d3LVx6nt-7mnrMX;uO;)A$Ui|x zY^p-)I9=Sa=V8qe(W(l9okH|8ZT}W1vLPidV-!#50?WuQioD_a300Gg3M9lPk6vSA zE!wxEq&fS$ZcW`q*r9@b{;B*{lh%hexQ(tv7=OZOgd2bKk>I5DDOrz(*hJX*mS4HQB=`nc{BkL| zNGXpVio_9Dh7#8Vs-qZjGPZN5`b|Lfxqm);2C7pL#Rh3K(d3EgNo@0dl`kg`Uzx_U zmv5=Df^4Wy6m(h__pTP7Xy-hv31VL>iJ&&s?r3H)&}=kSSI-=98l>1Jyz5bQ{!cod z@%XU0@G{lArQE+WaLZ3icLEk%#*s<9l&Chf@i--hKGQOy=fVuLOr|}XZ82o3fvRIJ z4CS)xAicKjCifHT62lWr(<8!m*v#$t?mgVXpfM`>o;t!Repf_-S7=^ogzPvu(lrJ} zW$jkh_4(LFKV7R{G-uxKyesrkGfPh`&vj^c^Qo&5^`9rYKMKLj_yoGP1I=IQq}-fG(PfGQ+N` zGodn~n$<;<6r96L+Tor`qwJIZ-10+~4@SC1prG2?hZ@_#C9ZBVUx_reNHd=@L`2lW zamkx~YW`9oIaPYP#d|m2I~zOzu1-Zg=7d_MpO5T}$-|-mlLG_@t_;lVWnayoBz%jt z_LhhrjgyqdL3ia5Hd4$qCREub5U0O>GPS!Mj~uv{Bab_H3eXZ!`0kF#JZ14|ali4eAtkV(5lz zSuMGv>ev36AyS6!69fRj)(FyQ0|hx=X%yt%J&X9I&kaRWmo%h03S@WOIxup5!u0)l zghqOnp9uN!)#h%Gy4i=t^*??z3fdw=ZC&KE^d~Qyu`UEcgyg?s6WIE8cYIkO12!H3 z*2BogTRA~21CHw++vAUcMwJWX0?$Ao_ zD$?1&FE`cm!$VT4-oBW~O$5Ji%t#&^rwVe1q<~q1x$-WvE(Po{X@xH%7F^g1!M7HP zWzbXcNVA5^dbt;%?A;Kc(pJlU?A@z#Eat&@Ac{@kB(6uoQ@n7~XOcP_fAEjq_LT2* z&AiFX?LtBu=s6!IpfR!Yz?_H=zAaz4-hB<@!99>ehEMLPx6B>oXJ5`fhHpLm?KWcyJ(I#=>N;7WgEbefh znCS2T#FELc^hY$&_-2%Xt^dNJFSC9k!?6+KC>{IC(;u(+DeMY+rsx5*-*}yYK1@3smGk#~x`&~zcKbqA{l`YJUqghFct7fH zwqix&I^i@jJ(_HuI=hbbAxp)Fn)kI+!g$t))U&7*xl`xmFbh_FBpdcjbLPOWg7z^u z(>BA6-Sqdg>t$@SO9#?+)uq`v6!=Ho8uDUjMI*^OzR zf=_-fbT(jWmla5<>Kxyjk%s}omGe8I?QKDOs#iQcfOs&r+whPt1KH?D0 z_TqSoJ3#rM?JtT|N!G13RsVc;Ngr11ZxM1nJbXKGhB#I*@QSIms;8aYEjY6z!SzEJHRP9T9H)6g< z6W8o+H)H~cZQDZQWdIi~y}aKP@Ak-bLNAQJQj_b4mEc!}7z*t;%n zCwS;*gn|xty;HZ4x)xMB`=i1tSFV;gz5i=5d-rVYjRI9aMeA2<(A%QfElIB#X^$2U6&J@&dnA!A zK$YjDu($7-eA_uO^j|EvN!({-;2k8tyXXSrIAtFQ-NG3PT>S8(sL3sF7mJ zK>GiqlNLZ*=c8LSOtt#7pP&{;+>Fg@ED4N)8%{G(X^$f>!fQ*RAoo znr?}1OR2A+o_!Ua1^raB`$be`_0MOm1w%B06?1ns=#TV(8?c=t+&e(rhVw!Kfr_!; z8BjeUip#YCEFvB600Y>c*A z(soK_DO)Y@oYww!-XAhqI4Rw*DtoK7W(TqVb@>@begoX_lTs-@^-{6#Zn=6C=3>1U|@vNK|Ows z99H13_0Aeu?QHQ4t#~c8EB^r&=K&XMc2ro4srrNF0GEi9IY*Pt7rmTNN=CH?l-VU4 zaToG&L2k2w^OI2*1I`y-`0X$;Qc@eA>jzQUXXW<44Uz9tE$LNLQLnl4AMx3D?cs7> zS9~sl-RN70G@MwoJ`%b0sH`&Z?Rdh44jN^R@DOV(G99YP{6`m_tk~_5Y&H|8wN4E* z&%&~ON3r=q{@Cexq;hBad$@R4qQ_Hzw20rfL5*ze6Kl4<3UIf7QM`BH$fwo~&bn9C zV8YtiWPG3}x2h&Vnu!Mseh~MSf(GmgTSH{|6Uh3ruc^e5nX}7#nzP(Q{5rsPt0uLM zA5t9(2BxzJjnr@*mxh>peBZBzLz ztk~X=WcPki8xZj^ZQNg?9UR8M(Hr#taO9tv>O9}0|wisnEB*8KCJBce1@iz%;$Ou@;zBp5k-{LKlQ6v?EI1ea=C}P<ShPgol^) zvDQn`=X?kC$IqI0I)Z054lh^72SXwt^1}c?3b0ewf$6PZ^?1qU?sISZAlkwkQ|Zpt zrif?A@A%=V5oC$UV@v$dba;+;((*3wTb&GsHs?VD<$`_cu9&?{E%Sc@Xfnloj@kN7q0^A<$;@BY^5QMB`IV+BIM7agX8U#Q9sesA$JoFh(TI}Do(_wgj(cRGdmtDI@9 z98Swx8R2Zp``djKySql}+v-#0)}=Tig$l+S0nkp@Fh zbeo=HS?~s&UN!3y6aUuuNrF>fMo=XuS&(Lyw9_T+;sxuSuyZla z(CPe|@9g>r{`8%7AV zEpoj9{oqU%{GhO24e7m2Y`(b8CCTQdFUUaXYGmPKvCEnqyH4efE#vqDW*2&;ImZ#< zY3&Cm`Do;(Y1&acMsv=-Zb-%{DE@GFQ))E);V+5! z5=K*5+55TzUDrxXbOy~L9pw;DA6x8i6RzI_W@6#bhn5*xDYmZ{=|yhG2B>gJ!enS} zS6KzEkmg)2FcBPl?E{lb=23plS=>xnrY1;}IYRhA@XMSgd;`E(vD%?3#r%NKb+wcN zmtN45E%kvCI~%)>$-8`ReUWEY)MM6fA!y0#AwztPXoAunta-n27%^3gvyhgXXH3z@>VZz)?;;-Cw(xu+ZWn?z$FM1hqli6B0W;KYe_|X*E{kAjr5_;Kn+M$6ZVH)|fzM1b4Cf zYz}E@VzfRg;hu7(`Od7fa52$mh=YLq%IqVMM!IoC!@@hvtb=wKwjRnv%^^$L$J_zG z!Fh6dL>4K9C(Z2322dkJw9xNPNbn;i+rQcukrNzs_mMztQ@RQLt^RxiWJ9;N&=2Yz zpEp|z>>Tn3PrL+Q0-i0i-VjxKRma8dn~L3|frqj3eV(<7c3DAG6`;pGS#5{3t?1xH z(|*=1Zr2##`_OrApYs|7idY)Kn&!hNY}TZX_%*W18~`;q`=mmHNLI!Cm4%%idGABW zld0_wGR=!K96m9FG|?WN`k+7HIY#)96Fj&0-?7#adBee_Xr4I9sr3;_qb*|quVbR~2YRY}Vs^h65qezdD1P3}72_2-j5})L zk8qg6jebCsmqrn)&izio(ZS}Q^zuWSb6?dgB}%SdXI`jFAt}pF&)e_I#-5)a!5_h| zpFZ3QU72@o1uLPjM)zV>{_}bqbREN)LnhVbd^X}+>^kO;zm}{*bT^c6SA2u*8=#%l zWJ}C9f+xW|Ws#zla1W4ECS(7@?i|mw4Qwrr?bOxSv6gP89m)&$`c09XMsT2gwKm&E zd6;`M@iIS{SaFU0$Uiqlgns`7a#eIh)yBGB0=(ZXBB3y8JlBj}#rdA$W|!j)edQ1< z{spUpqA_7xVMZDw2^eI1hZ+26i|8N^F+1wGUqz8SA)IJ8LL3smy2yO;DG*s!WLIBbii+!;d4m+Z08si{g4c!<)MSihU-7cb3Seo;~wafVyCm+ znY-{SHGVE&#~8-@JWxniv1He)p`pg>b+zP6x?>S#q6_lvL)%lRnwK<_gPCD!)WY?j z&-S!p%1BWnVY@dCuR!!>thG=#`b;CB74s=@M0v7&7r9z3TD3?|#Bkm0L6So)Q|EI! z5%rz>owtyOR8=MsXqE`_#}uYo(N*fQhY+r>Tp;rKDGtwD<@lzY8`%?H`fqy=vD=Ew zwV!)dD+j&$hnYrTvsp}Y^n-!Ufa8vl78NOnDEm%1_pScBYRx;pVcr-0 zUT6wsi+gLdgrdFEjj2=UsH(VVL`>Eo8*KNFDaG;tiv0V-GwTLt$Zr}|vv;mq;vo{q z=?2&A6~bJaaW_8v=s4SY4Wr!KQTNGgxGGUMAHze}vdQ2S!~87P%5k`cD9P{MQ#!wB z^blqd9e@>)iosUpA*?5=!p*cO#$W(l*cwai!y6pA_ zM55^RvJ^Ifq#!>e>}ZMBeJWn$9UcLoml`wOq}gqr4R=LVSvN2Ow#-?>lq*Oi)gb!q znq0SM1DLfD*KKxZ!|#Vq2P2!pQ5+sF;j6DB8e5n_eYv`Q1%6mEMppN6I?z2d-+PS9d^Q=G*H!0W3ripK6ru^@XmDqO+&K7B1`)DFRu3+}&!cxv=F)4xjNmTK=?*j4+X}Fpj z$y9dD^Tt9;7!F-wuBR6OkUadpGbV=&7jHyy}Tmydd1Im8f47c!Oc=aB``_?aKTtH_QjG)iIa+%Q!Qg7Meu?n`hFxVA>Fx z`kDsruHxt*Cx^`LGi;sLZ|cLy%hV6xeL^{J!>p@OJvGX}Bv(LYve}-#O_L!{#MaG{ z&SUQwI_eoZ8q-7}LSgt6HP0IIDUM#zB-#jLXoG3OzjS;07^40So+O}9tEe>#_5O(jp` zOfa6}mqB<}qLc*t!**N-_};Un6b0Ij%l>eD>S9uGOEc&ZwSaZNbKm_y7juGJdh)T%AdFx!c_2B>Q zLLCyl+Z%M2S!pxXQ~dBn%J@6BBgX{Tv6O|gI?^16XD*lk>~pQ?Bio@M5HDxNcB^Wh z$$P@Ry&w+!%PhH$92ThT0WOPaLwQUy+OMu?>AE9DQ0${)1+MnQ5?+E=sKE=auWsF`=`PrXkGi!rCsO*gL3%1?u3|k z`Oz}(5HJ~)ltV9ch~8Tu#CYcVXnvdf#4O(Ae%MrA@;9^-&z-_l56q!QSc<5cC!9h= zA~>Tp;I%V*hq%GPpq(v}wQL&l6O3ac{A|+JH6+WUld*-;LLC}r&mt>`4+;MnL=#Ug z{G9rK!pw61iDA(%Dy_k&P4$Bkai$gm-9buB$G-GL?&+`I7S~$^M*nx&1c<$Clv^1T zat^E&ivo^%fqaCBH89GUe@1S`omSKjPCVjv6pOQTyN=UZdXb3&-R7kkg|10h(9C+^ zhBVmv7X}DVGIe!VW_OD4x-b>e_^{Hz<$YgfSOr&M2J97NC;63ChUO>!$qA~cy`TQS z+!k|2U{K)Nzx#0)LOE*_2Ci?7Yv}H>YZ*5iN`2{I{i!5$>KO-K0IG>PO+|lz#4HbA zCOO;dFdm?hlWO9;=mxLmoIVojKVx>Yc)tati#U#vZre9e=6P*#RE+0Ml;9thAq|(p zVX%RGQsR_3F;ecdlq&*;h~IgxDf%=`NhexL^ufOF$F8`IrN1x94KKN>zomKjOhY=G zaA{#zMbGt`x-8T^(g=~&R!ep`xnwnP4QQn2!pO_eEu7HRAY;so`aquE0fZXXBTYx9 z_(-kdE4t4PwSdS~BZ<1ouIX)i>zVI#E~Z)BrOirv>sgW9hy_SOp`W19GjT(H9PtJbCQf1c3c zgS@oN-46<+uV}mjS?@aaTQjd(=Aya7ybY0nQET$N|M~2zMYuUFXDEhjdny{||7@C% zOj&QKB2E#dRy=GMePgq3*4D8Hi53@!V0+1w`R)m-@)G&`t{}bX3r)DAf&eeZ$}bmF zz{bbF3+b-7IlI9=BBR$v5SrUsyr|;^GxzOd?mSey29c*lg#VrJ_oHJu#6z`SP9JnT zmbbuO&%+ey|9ef@7(3zJF$#l)`k=^C!Au{65I)B)gzD2_x_DD>UXqY@A*XcFjx3?R z<7qs+zmRi^|7c%R`}8h%%KMgxEl_h#D@ga;_a#_2nK=QXu;}!Nh*RIKU8Ky9h3JiD zIytNLM-&hh1_bQQq3Lg@jg9ECB{$^t;KDBR<-#*e2c^_~OY^NWly%gD5;^^WS?tGj zJ|g|+voB+#AO9KSCsN%dUi@p}K{T=Ga#{f{-ihe1Gnvj=$hF#)$rU!_&MY)-8;8HLz4V^$f{S$qItZSx-7J(Gs4is0u#vN9!4ibEFvyJ z#jI<*8ND@O{qWN6+2;d~n57?v4rUF1uo9}WE%P6TlWzOGn#S+B^PNaW&U8@JxoGxB zqA>nlZGvs!&f*9zfHue7{kx%96|}3>$mSsZu`F=(eN@R?6Vct|77=%m2s9Zyw((Nyq!N`#jS&aED>q|Rn_AfmHyw9W{`Td^m zEg|4bKHq6HXMZQ>UlkpCJj+YtvC!drPHNgM;=Yrq)qs=bqU(c~!!%b9a1wv$W>umr} zJ-3lNr$@w^x>pe(Vch#v z3*wgoq_|5xZPNlP2E=k?h5joxzkQ+Tjbd$eWMtkH-adQ8vvVUSvOd7t zHOoU&|BSXr6C;;&k=6wMs>y0HG$hX0$)MKyn>KJOXp=PFzJSFy5t*CD*XFM{+Lc=Y zK@2aZZTjL$u1=|hV_jEgqQbRYz)7oUNuK-%wDoBH>zJ&j@Q?t*zS|_~o+n7GMNC?v zBxvo3cY^L@|198SV&8J(2;-Z!fYwgC$d|4X=i-uJ3{-EbaMoWaxAGp6f#+3BHKw?Y zTVY!U!LGs9*6d^#B)Fuz&Lh>_QI@afzQS7P@@IG~E>&I4UylIS@n`H9jXP}be#&tu z+e9DjtZM?-gnE|vI)9yDT3sr1c&#B&uDQ-E| zx#_Mp={H#SiN0UZ)PMX%H!D;&)Vzn|8+#}6LQL6B>RJh_?calrE9+C1FX~Aoh~rvrcYuCt!|CFgg)c1HTUtq(5y#@Yn=VZ9HD7m@8t}z zk8mAS$84hf%?m!U>_&oAIKkjz86PSa4polC+?k&@J84_T(_|toGSnghbMNR-wtvUN zyvHjN+fPrwzjNuG(?-F-q8~}n=f?EuL~c-wuL?9p-^uf3bCqTUt#)h<8Hx-3Tl+x(YDaLtRy?5;wfyiMqrg+bakn!bSWh!lk+qB6qxOMMaw2a z*Ir^O;m5vHvjA*zsMgRbd%ivRz2a>4H{mtPw+ERzk`Y`7wb5491%Wv@MRfus^xgbv z1`*uhh00A`>ZlHpYB0@lflr0bv1q2Z=Y$Qk` zVF@H;07=L=eLj4j|L~i zbj-+bBX1&~(*G1xazMA|hH{Q%>0YNj!h-bfNLvggXSLSkY?9Gf=BeY;Dq%2LphA88 zkTNR@>$TAI1NB#Smzez{(NH;_&hb|bSx#Q3So9b6CD=7|>AW1;W=AXBeodKGEisOx ztssn;H5$OWVxgnX81=$5T6k_DAk{7vBDYh>7=CEbw^z48*4h%y+1W=e3CAZngc$GU zP89GbEAhiQ?hb8v4M{;y=yRvr_RPOM8Qq;_s@yhA9LB`zy2zXQcB_8`l=q5o>uNe){-uCfE0b#W0lgs@W0=V_N6 zZ2r8`x@=#XLn0ia{vz9!^R?Wp^$k1u7|_qGr}v|-4{;w@hVb2@+ryZ{vc1*j=L3x? zIf2oJspzwk<#ht{)}q!U#0_fDKJmo-&KF6!_0QJR%?97};*K_77)8QIZP@OheL_E- zajJH5a!mDLF*}%=H<3BqE1?Y)EJfBlp{|!t-CY=QKUF4sJw9L$>*8hmkCF2=9>{vn zMf+la#oXZ4Lg;Fr2=4Ty0XcH&W+YuKIf^MK`0D>%Vf!pD<+ychaLf;6BKFXFk`Tg9 zE|vDHv;~SQ&S{i8PHn*@gar0G z-FLgu6I=0#b(gSFyog;nqru19#PZg+KcmE)H7ai!KRo53(1D+ifFUE`yCTS;rD2m9 z;wTPb2o^J$UP)vIY9)o~m)d!_E!pqE**-WSIZ>*ExHhhyuk?2jwJJ&U?bWq?5hGzO zLjBHDP(gYr5v)E$j9RmpnsFnWxXXF()nOKI{&|1?RBk-q1O3u7wNRa6;@(l7Y2xzI zC!hXEX~`PlnU161$niJrZcy#iFbZ2`)U@?p&umJ_`nY; zDGjz?Q%fnCh4Fq+nS3MR#Z3p&$2&XFiP)9mSMpVjvZ2nx4^4VT-1YUKZZ`2)r~o?X zM|=Pcvu<(baTcLS{ug_t@|yGhRysrmHQ~HEyLgyPKgO1!2^RcC-}9mb)x$Xtfjj8; z`O*yJfvF$0wU^;ga*9x{7Co+SX8opSMq`?#>H=$m1zt`ox~SSPk5%Z z3ez>buya#YGa(T0?)kARn}qQiLgS08)pR{p!cg?;>i||s7gkbZS`*D{WmC6VHonHl z$g5}ihq_wJmMYBf=V$w#qpx={(mZ+}M>*bjX&MJdjO7eLK zDN`wEHx3j=oK4lF6SZAPY_1@f=BK#_2;^urNH2|n9LH-x*_h#jfF1IJyh7OIwxaaN zP^_lCHFa)>h3-EMMj}<>qT6$cqv6vgWqq~_uR#IN=9EQ-4@QQ^em#vCaxBQnN9NhX z*%wXWYOBYzv63Ow-!dFyfd(3S*wvG4Jfp$1zajDWfm0_R$96cH+uknLM};*;=Vz%6WlbNwr|hgf}DTWgZ1H zb&na-8(KFC*)PEQmGx^c07Q{Sj5Td%e5kW8nSAuA+`|>lrslr3;Fjes_S&MdHHaZ)AvZvoOlZVljA+fB3 z27CQs?)B1cpi*E_(U)8Q05?L2OLwy|anRGH`Efb_VGR)5c%Ixt^2a^-)JTNrTa-F_ z|L9nN4D+6KL2IFeoQm|~a;n%SPh0h62A#aQd^R*3WD&G{WnP$4f6(>E-DdyD^e}h| z2*8Ox7*9M`Tw3DFrM1xMkGN>v&nw0&<9Fx5OJQifASE!*Y|u(4F1;<%I{Mqk3S1Av zU@2#1FLk>n17Yb3W>*0BB z&n~?#ZIZDbS_VwBrTZRg_D_7L6v~ZdD0Eo(z2+;G&X`C>|6eh`z3dsEsIieK%w;VM zlAc}&Jy)K!k11n=V7dnY_imiIw@L$&_9xP2s!eUJOqw?88<(+R2D-OSp|Es=D1F&9 z;A_Q#bm`l?j1EqDGU`_lyhyl{1C`~SJ2E^p7Vh&`dPOO?5u^gFk6L6>DW>K%@x896 zI*?#+G%{ECb0qDnzKDjEV;Rl(Z+t-@E%eNr{%auVn8ne%%OPYREt0ir?c1Bu|6G1{ zPGW9-sh22J_#Vh7-1X17W7heS$7NTrW zIe2lcq{Q+4Q@D=+kxNG$8FPbu+!c;4Bp73wK7_C^>txxH+@ZBigJCvT8~KN!_|?b5 zMZpIILE%3B$QNvGy&f`HcqEVzen-~?|2fp8zm*G%-io)1kBZV>xaX`5U;j=H&X|i? zoVU2o#6(}}vSzGpRpJ(L%VM2}nlt_!0m+0Y7UEk<|#$!S&Fuee4?%CK~2@Z;sIep9}71& z13iY%FD-^JG--Y_;TzF>t19#?!QB7-YaxlCZ;05-L(BK zcYw-eAFq=0n!cssllDhqmbQe#dgn-OGD?V8j4Rg*$A$tTMF`;bap$uUdB%(+6{tS`Lqf;+Ghcaj%gJ zUaLmt+jhj~MpJ-2Zdw&<$A??oBWgvxmk^IVb6d};*dLz%Q@)3o-agO% z!qN7EmKX22qYvCI0L?+HYp6~xY>EyKoM`(mV__KecA`ABkIEejqMl;;dQ1@9HfHh? zBBUA>vL9l&Wt*cD1mjU|qK%2gslE%z$6oY}y+}nL4ZF;H<$q$V%|qWO_;f?&Ogz%? zT>c89U5|UTT)P5gzZ*5rS$sG?cs8!#pHohsqw9?k(;(EOzl7WG=Wf!PfvSY1tW!O} zPE%*V>;ZESX=Q=(fq8ZzxjZzc_pprikYZJt()R5A61QFfA3ozYd=W569NXe-IL(#) zMb7C7V!ObE`n$NTuppH-M0s_fC13BMl16GCr5{>(8q|I~!)-Gkpd2wWa0;X2t zbbm`&?1&I@p=BJQDd+os@q|p7P^8a^-Ca$a8{+nR7^!RrGd?jYnL10v!L2WnOuaA( z2WP!O40bMVB;yZ7_5`(vDbBl&QyneLNk+|=0>5lt<6*;pmFtbG!>;?p5>-374$`FDlOkl$1OWG>}zejHQ9 z*(F1@!ipo>7yCw2q6KtRC@t>FebiVIq&QOe8pLELHTJ`Q^Q9lr!!kMj;17CMKvJ}Cw;a!Z|B3T zcv3m(bzMx=uXbp1=u_A2q^ozzFFM(2U5^ZuI1eg$BdxFi`Y62}fRRryhMwyCI~YrA zI9K}F7S~5>pO2-Y7azt|4=m%#{Jr7A3`bV%5Tr0p4i)?r7ZMb~S5e z?^(G|i)(jG0&I0b_q6Vsvt>j7B!Hr{g>#pa_4lXiIQ(?XXR}*FneQvJZG+gX)VB$0 z%lYDFA%^WO!r$IH?#02USb$^~@&Br<`3Wgw*2@rEi3?-WGk-=M#|wlfNFMI~6qV>y0#X&WpeZi=pVA{ac^H_Ld1SE7dixkagE| zjB0n~?FPU-OVDq+BJuOjqz9zBjfh8A{4%bjuiN3BVVj8~IhiaM7SxHHuC2sl*K_ z?M+k}g~Lbeq-J-J=<85ce?c9EcM7)N5O!>38Ta-(4?S%c8LAftx$lQ+5WPI$5A82Q zvy6)I4OFW#`8wy-@@)h@b`mB}l`J9joW1%90{wj6yP~@)rKS#vp42{+EO|-o-MCblomrZa_Gjju_+H?4L&lC^X2Y#Cj(l^Ol9Pf%y%|OB{ zlkis%W>7OCe=yk*OA#4BLCvpZaaG*@xEUF&A}DR|moV1{{}(9B-k)0R=kfQn=@0!? z#!f%^{z!eXOrR%(&8lYh0BS*ZLT>Sh<>SJ9-==~LHZ+^Bo|jMJ?`_SvBYw`_m8ag& zxb@E9qf6I`>s@g}H4?;@?bXZ|&{qpDc2TFPypg30i|iO9XKOLR*kchy6tOA&uY zu!gQZ-g}}4z)44IxDW6W%+k~ZeXlZSF*$#zd z7yVbk!jS40LsNj?uoqidGpdo|1U*5>>OQD@5LtLUJEWNLd|bC-^|>{_oLjo}I%ji_ z&P{tHSQC{E!-~PJfpa*ZMOVp;#Tvs#?>st+V-J}z(9Z)bi(O!XP8k)hTk1ug#ep{+ zPh~m4*+NMrlT?h^%T+03P_V}298S}_|4`&AezkM@2V|$_!6lz<+;7SQy^4dKqv&8# zMby3>gYfl>-18v@O)5ev&9V+BptYXJEp{#Y0+Yh1Q>X^TX}E-Uw2G=9Hy|*sY7G5| z!vq~bl>nrFfmh9Ds=pwH0*6d7eq+IA^aK`gKBhpX(@>p!zFhp(q0c z-izXD0{X7@leklpK2_SoY6VYZ^qRGfOh4YsEq@;QHMO~hb>Lz9>LeX&{gfwj=OmEIY6c=&^r_LSE-2C);+#^##zRNT+bZB%VW37~AQ!h2g8crj#j-RLt zP`lSxMd^jW0RMj4R9wThTPOEi}Q5P$>F#M7|Jj^L^(TJuM5B|{6H-%hH%C&7X8`#Gk!V&M20BVeqde}(v1ODrkYZdQV-2RL16@)B2KFt?V(opi+GxCOh@>j6ok?ERq@-HuC8(qzXMjAL=~M~P&sCPwV0JarN9@XFIt+~5t6*O~$Ul(h^kYu7n0iKp zSvzZLBll#nf@_c=g`b~3cW!@iu0DO)#{R1AL}eHC$5E`>EsP3jb^Yw@eJ_;)gk3Z4&_2?KIT}5PM^t-`*x(3S=wZM7` z8W{$tVS~%)T&e|VCBsv^9&4mKVPmMy2(kxJ_tcK15b3kMWHHupte^2T?gT>_@hqqA^3K zVX!MKFQl~xZ0~opESP}|RW*%>0zWR%S|{D%$?qFqDiPGNjMXh;uK*etxp{P+RPyhN zK7^~=H2QIm-p4edBkp3PvvYDdSh{B@VP$;VoTPTq84?2v&rc)u{bmXz8mj*fu(~qr z=wrLtNIG!Bl;avBKiSb-0F`eW_UoLSiAm6%2vl(UrNPazcM0ZMfkczJY(t114=u+9 z(c;;*8za@UOMhK*%6Hq$F@+y;OH8Owe%rH8>1K8V-0U9C45WUWTNGF7z9(1zfg5ye zhIuz)+EKcIsFm|HyzLXkCA~_@W@sk-PaIM)pLD4Ou@%#XLm4gTs;+C`G!lA4;U9i7 zea4!uzZ^Rp_<@y6#S=++Gd>Z~-*+mD+n?6l6zVT$@j1IdrhAz8N1f_-D)GuwV%_a( zxj(6TIUA%Y?+7LCGDgc*)gLU{pbhhGqI!<#YL9jC&M&ySLrTyMN&#Yuyh7jwJejfPx2Jm zH9Ji(B?|}$nUD0jXjY(iGTR(Z_D)Q zZwEH&Kj2!V0Va+X1J}=4O5Y1-H|>di+?oeOj_7+fmTw}xvHKQRVfNU9KBs>Wc~vt` zRz%%yl_u^bv;0yB2dqoJ#T=3%U(P7-zYC4ocJg*$Ea&xwnrEEp)zw>FoPtzHcaNr{ zkC11qLK_obd|xF-&D;;W;tJeNcl;uvmc$v@rxs}|91XCHK^fz(jIr8RhoS`(@aO+)yY zCVvM#DQTBBED!FMI^A{N0miDuzAYzP|6UpZhr)fx4d}sJbv9F??`gdflVEOt?o97q zS_jvdW2`2P-e>B}0(SRakbCi&LVd1EGQ#|K#c6P=jak`@-1Q+Sfn8}9P7#>C(2tP+ zUGa)HByEf_Ote8vXZX>|Qf6Stw)DDlLJije8oj>lGDecKZHVbr&_kmokhHu*%jn#i zxgB2ZlYiMS{>FK267lRLlQ7&wIs`RIvf%R?(2ksFwbLC3ZhWB3Rp+~04YkYKB`}xa zU&s>M0y$Uv3wH)5EUAauGN$Dg1l5+*;8WyafwzrUYMcH;Dt1mcegyrd2unAs$U@h0 zzgV&#xtGFJ-j{s9eM<4Z28U~CcK^1wmVMWspn=_egyE1Bx=S}V2!EeX&~3MOO~6$~ z2qkf+A;)$vds3l%uXfwa%A8GoRVKcknOh=wma6qgyT^Svh9ODyvK+doI)W_rnVSmM#no3PJ*oHFzG4m32C7W>7ev4>MloH!u}KWheqXW zyT5>4{SH^> z&o=WsEmSrWj4XfKRN^?CieSw((?eg!H)=7>YN}n$`MU!XRoNX3zOxDDl@bK;v+Xn< ztvUejT+%LzfPHGfz2|sAUuA}?tEln-n)To_oxkko9NWIqMPn<1sxI!CtCAR!Bx`*Y zdg(N~XJ@La?#Ou2uD*v}EtBfM#%h0K^M&q=zNIK)Ld)m{O6=6%v{vU0FZ$T$if0D@ zS>j)2)Ym;&h6Y#dPaH)Ibic}t{*Y8{4z+ejCP+4FEmTU-7BSr}3uU~@{t{y4BwOpz zD%7hU={Ajd=9s?7+#Fd9n#DH&^lcPEMC>ba zj4QkALN`)12_W7&XkGM&mQdHy!7*l2ESY4ToNc7Xo_V1dBhRME4R1xn9XBy-NueBk zP1&dPf{QV?GfJCf$(5<-5%suuG*qe~Byq>up`uRDLT3QKc#*u%3LkY^C+!ly9U~av zN=3bDdcs77H(8?6;CrY(|JJ2`&CTr3>smj=?NvR|Jl zFkaP$7iHCoa=xmUuhdzjBB363O4ls-7V1@lReT@sPHVdZK=ei0Tlt|#G*lb>t+>{?dt(w%)y zF;$`hO24ofYf3#((KSbP9iOTDIp=bCTcpt=bEU_dMLwS_7}L6+=*{cpv=s#$QPM|{ z8}#9=y=@h;jD&p!&@jE=D1`s6fck4__EBHh9PAj28iZ~3)!*arm8D6Tck?|{Ie7;KW06Pg)v z3FdAU-BKTzp{xNVIzlThS;$F-(|c}H3r~QQsX`|FuOXMz{N+57!#zP5UIUQ+tm##J-ZL>4)V;nn>=48h}jS zhP}xwue}hz?q=jt!|cqXr3arICKTUP_R(6V)0{UfcR!hR}b_KV~pNzf2eIChM*-F$F-{o{F8A{v;YlGEqQ~%q0d>Gv~{`Qi@DPPjQQuRS) zxK@1;H^lt-E-yB`6lwGjvDOn4NlegRu=sFXQH)ogz>R*La3Zx$8`(P7139VkVd}amNsC7{~Hy=AYgjSV#fYvR2}AHrPD zYCrY%dr;OjS?u4(8`@84l?287=!{?7D-aYgZA84px|aOE`DC#8?xo^HtS^K}b180- z5d^#EJF{=8v2x~lc};e>=mjDwfHw*KlW6u1)N~1WcK81gVK6=Jlm5scX{;!0(FAus z$2ingPfF7!3(@^`s8E>zDe(_Ym_@>;i@&9m=-TI;{?qH$vnVy-gADY9TgbMwG{aj@ zd#}xn0WUD!4{7Z~#9lVhB4cFbjAv#9QkQg$&DC7+8tpILK3F;Jh#^u63AB01!0FCO zpJNOewl*Lx;5$ZxYgQcU`q6M7+F8_gD5(N{ua1Sqd8fWu8HX3ke3!Tuohs+!{ry!T z_b;^!#we2w7X3rGeY(>6guxVMhatIGH zwA(^=)+P1gp{)++h5o3D)4dUmWLa(M@!1;8$K=*aq&({x&IO<2dGu>yAoWEGbXl-JzM(ru2~1sqOQEe^)g4>B=Y@mJrqJP@-TTOdTw|WK+7hRti?91aMbf z19r?+%&>UH_-xt~rgpcJwLkf`pM416j~9Z9{AP^j?bAz)oRe=Y#~%M(RrSt%&iD<@ zxD(#470KoYt1;LfnzAaLztUOAOc?Pnr$j1p`)u~?TAJInY>%-fp)fdR^?^3Sv~X?m zUEFkjtgsQ2biL{CPNti-SZXs)o|VYRsz(>EIF-`7$*wzK$AKLsni7l2_PDz~=?Nw^ zb0vA{?%2vD0fEPzU>%i%wk!9RDra?rEFiBan1j`NNym~%IH|c%v=s7=wn{B{$7^Q1 zw{wo*UgO+)Q$pHsgz}tvRRLvf;<=iviT7MQRZElCibrQf2hKWgj0_AfiD&NV z?XfExLqC_V0rk_3YTgOC|6{wDu%fAHf!{wmH{MbBq&2gBWMl02b)i1V@47NomjO>m(i9Qie2;lodH@idt?|V@^`$^q;1gJHbj(> zW9DDs)^ckAiC#n<8q?ymnCL5kx}V@VhLwpBwJS7Pt`BCMq6Vg**bhhA&kE6r7#3fw zb1Uc!hn4cfja%=TlC*@`ka79q-qRDTHHGK7zr!*1Q+os2YMgH+?)A}^4|jB%WuTfN zA5&BHkEUe>)BH+Uv8qTI-F)QI71l|8uC)jDyqffpx6YgVu0x&9>v(bNL=}`FD%GxV zLIo%fN)oF&zr>IDwPBU_FpI;e&l9ga`zrKl*-7=EvH`Y5ziD!b`oue)YnIzGJ!|st zuE0+*c-`sh%&Hn)MMis0J$LQ2928ySm)*E+Wbbx!T18f1PIUPO1*~P!J8$Ih<6e%+ zoq7m|G<5Uk*k7z1@oz-1KfCJS(78s1di%v`W)^VjRCTI$?<7gBPJZjQqclWxyT|*} zCAWkR+CE@O93^Q=5cRhnzNRb|?X z6z&aSH1tD+oPRpE9rF6Xm8Bcr7HrE@x>e}87a8?{e~cW=fXm%g;#zm0Ib8JHx$nD1 z7+ZC53GQ;Q7Q=661Y0TBg4dZNM!E&oW9D6D z;4T}y_~%8?BB#j{ZcV~q8-|rh_$Bzv>4>T`0=EVIUL7x*cYC1dB5K9oX(KBMGgzd) zj?H^DaD8Nku<+L2(c3!n_0%JP%T*U0&-TIjl*p~tebNUoE2dm+N@io?8>|lobXp4t zbG-oAjo_F<0T@2%>6HM;fd!~#i&^Kuux9KepkNFfnlhuI#GGH|yhb|nRJ36+^VgRr zH7xD9OGC63K@W9+c`eqR?tcP#Y-vHdrWJtL7bXl36u-G-02cvFkMi0P_&sZgM2 zyi@4fv$Zvl3ce-Bx>lg?YUNLb?->SEJENfmlf77hKUl2|L%$x(HX7rBXEOCy+0;;_ z$xf}MO9jN9Bi*6Mp#BkZfA%FyJkyAqS7pg?2StuOoBV=G0xb};2WOP@0o~y-ULrrb znPKYVJ*_brF9Z0(vmS{f0AelmZ>NFW5ZH=YkKGQsYj2RM2&bR0`&&=+)U=u3|3+8l zvKOf(d{5r+YAdrDS)aY${Z)t=!d5K0QMvWHO;Q!IwshZUy_^|uL#foeyDRpkw4*T= zBMJhlW`(h>cB`B%jqa-J<5P(s^cf%O+DwaNCNCN;#9@xtCtMn8vS_!OXQH>x?bo>! z5;>nk8Uopa&UA;_1_udlq2+}h=lNnFa@NDuvp(w_2N2`?OK}qgN<1X!&shIYW)yE@ zaOt%VFtf%KGsjRKJZ)Q8DwD|_M~+hk$L6_7?s7Yq2N+XwbW^5bHgni5*Y(OXfF3wG zd+@vo6~eobK+R}0@kL!?j!bDb4P;Nz=0=StN(WzO-X9mP-_c)E`6+BMmJ;wYta)2Q zEMEo$(2K}PN_RJI#Whi?H{KEjQMIsltMBJzSN)gcHV$!R~P1fDKfYL3M-Ko8Bd$bf^CT=cT-9YH|8xC9fnm2me0y z>-H`cA&F2;zqKH|$H&}rG%}bhp5SxRN&rc5Q}pdp2}~F=C!F`t-ft~vc#d2ad_sma zmvaLCU16zWM6tcZ>6&KTRd~Lok=Q2T+BVw;eHx24IMavE0py(x5R`(Mbndk> z;A83B{8)FaXSrg__G~ZIIdqQ71+%J1o=^$0y^Te`a6j$_C0TiV!qXX{9NW8pKf87g z8K4jeF4Xffm00!B!NJ3!Y3q^6+)}rV!03d=yA?@d$GY^EEYbzYvvgeTIb?K0zxiN6 z-{q`MPO2)Jp!2_Rw$r%`M+-Pwsb?rYw8?P^>|)%P#Do4zH3#1FEHn(kQIK^>ei^W( zf-Uz-h&1t(zD;^Ji+;wb=ic?9F(_m0FY>^IIj%BldK&=-f8ydy*|&+;i#!Uaok?l> z+{kTF+{Ixv2L0T1z{I0|%R8nNb^V8WOs&T>VK(^$+21=9Ty0-KpPvS@Y%J0W@%3fM z)Uhz}C_5f+2^T#l#XTTdj{li0Pe_Wytn+J{oI#Bh*0aM{P|(qCTzl$VUt=}~SB?t2&aF9`h%Q%3*9t3NZUNX_JtWoqkEx0H64xCRG!tQNwhvl*wJ&& zJxeBp+bDQy&ThRwmshASwY-}n6w6(-4QbQA@qLGyR$oVF`1W#qBDYHTJ8BGAJ|qMQ zolzW_Jj{d+pFO`0p~vWo2u?`TY2C@J=8TxCst>rK49tx6^acG$1Lb|k*w;7J+HJ*# zbK97bujTdN8!{xiZ=pZ*bJv1)rEEbH!JQeu!yV{I)EPg~R(0rp82qj)0)q(&xYjfM z@I7xF>2*zw$-g)w*q%bV>%*xUbGuNFe&D#r7U8CZ9r%%JFp0F>aB=`HyfO61*fkW~ z%tVSEyh4V(HJ%Wge(`(US?2xQB^@OyMpx~(YZCgn*X2J9J!aisBwEMC^d70vi+$pr zky6pDxak1;f7Q2IGUvDxLFuU;A%W;a0J6Qqk1p|FxHp8kcOIWpp)qH>)Jl*H2wiz1 zL%WwR!Y>ppPkXMTdP?L0){M~ew90sif&c5*{$C9Ha`WGDq#|YQYJp!&#KCqDlLP#B z#Ukl$zz;HNS8L(4a0m^QI&#gcIIH-6-uiNaSSs<~A=F!FUDdjoxvE<3sN-Nk>M0ny zk-&!FvwOUdUyI{>m#DnS$Gy8XRc^GEAfD$Zw}1&)P?V>zc7E5At`PZy7CbD^fHV|@ zTaUFi#*W056H-_$&zFuu`ALg1YLna!Q+0Sl<|Ts8hlaL!(JcC;u~Xg=p{ zd#z@ffu0fHVQRTf!o=-#-1yz!%uZrXiHspJHS48z21`5B?dKUu(J{1!F=7d4(ApCs zOS?S?z6tOKx}W+YvMu!MEfElPQgsF(M!H)UYC(=4Oj*A z-8$@~f2To5`oVw(F^;X6tQ)F`)|Qz?rUCUb951)fY-G$p!RigBm^DnK5#%T99#oY8 zIL9)XS>BtMfs*y_tGy;2H-5V6eVf$lNjvxF8Rp$q*Wt}Mj&kl@o9UAMqzh=j)@1On z%==7DEl&6xdJpc}JasmO$eM<**8EO*Ioh+oUv20IHG>7L32ui&T2CD5oSGB7_&?`M zygHT@tclJZpUp76{HN;_@&&EwUdxI5TTX0s&DDN+Xv-oIowNOiNr^Bt>piQca>^ z0BMmOi_yH7AQLRr;GBi-8;&pZKmSZIUSpbnJ=ZR`LZD^@r0QjW3{{=;5m_}urqzTht ztaAumDlu?)8L(SkL$^Uz6KyjAu;HRx$4AYA zphYiYwN?`b$k<2!Ac0D;tQLYGci*dm;dw1efaMR?bf9b7`F_?WF%E# z)Gl*iH}dYh6|^@Ov!>>=v}q$Vg3a_-1o-ZiSF$8gb>J=V{8}kMq2Q(hBlM^J*22xi zfq}trq`7fW!j=61dN%(!GJMi49@Ui8Z|1F2jvBj}cqJ}|{)ADd3?pya15wV{veM>1 zi;Zf*oCy5D`>RM6zML2HR=u5Bs_V=VAxQIh<}%5ofGn@tzN=Zs`^2IY_u0R=6HINI z$n-#;wd90ikF|Fo+9^@8xbt40ysz%mx@Rn%MK&xxet_`L>d}NlPiT`ovEUaRR21o8 z5?;9j{IllSBd%KK-JdFZNLa_|YbB1t3cV&-6^`_R!f?QZm&X|;DOY9i>SWrQ(EHra z+G9lw2aj?sCh=N?n%$ftRo!q!CCf*96u1iy$ATiV&3nZe-LL1T1<@IkUX~xFp9#pM z(`YyNA9JVEA_ETA)8Qf}HMWB)w46rY>vvd57}4h%sZF`IH*ynMZQ)D*t}xc}6;n>1 zH#?is56ke)ZZ?=Tg5a&Ly4cxoJsGq6N|BqFLAaJ})HIL@Dr*vOlX8E2&l&kkgf%hn1lcX+wT@uRqVlYjv$A@Uz& zML(ywnP!lfx>Q}E!h8~SD%%xqkKDBJxO6(e_p-kMK!RU?yW zMa1iI4AmJ5?Wz2n~F%Z z{KrR-*Wti4(hTUYPfi~Us)#Gq2(%q_&}=N1e_X=<3t_B%uA{JmowxO~vz>kE3lV+D zFhM%l)>U-#+|0#5)4J`lQqyd|$Y1bH`d-VIF%dDX&Gc2n$TMx0S%x;PSZ>!CZE7sP zGx9FgP-C6K;R(IqL2a60eC51nx`+G#CIavt0au5VouVF&rM7k$wt_n) z)F)}gdG@(?Z*yH1(O56KMN`NYTm?4SYC&jGPgVlBC4RUUR)Ld?)GtYp(V5egOyLV=& z9u9YUE--G|Gn*6P7T*q6)dgxA!hQ_XCF3(Dg`6_xnITDEL|l&~54Z>In1hBIiJ=S;ZW7X& zlHa)XpJMtgBzR9b{pBjBORkj-)d_F=7QZH-LwSe^1tOo$u>99!;^B0#s=4BbX&Z_$`GH??zSJ2k#?G^&lFu85KFfwNDfg53q5-m zUK}!GWkD~SnSKv*X6{9J{PwISMpk;Wz*K$bdZ5kI%u3wl>VX~ez%BNcq7y#ydxNIN zgC#bzBmkE}m0OUOTsUpFfynVs6J~{?a4##0LLI$Hl#kj5%VsokWC4-ShL6Kl1-vTv zc>6*Al7+2t%;~{y#*-_Lu3GLc5--)}){;cmJY!V1;2}Pr0DE{!ir1dC^K3h&AJYEg zj^}E&%dUc3g~M<|ARtb(nH>3;?ThYt^91TIIstr5XM+pugxZrKlX18KtE5GrbwL?9 zCsYdp8icf|~R8@Y}A-J=Yer z#qBKNOu1g&!--+8J=0Dpq`GFG!E{Yt0YBAqmeuOAQHCM7{QNone?+j+@5&UMSfO$@ z5&qhMvT^>K%|hBrv%Q3QD?Wu5Ew!BXcWAQ9v6bBx{2&M3U_#&}G&$5rivwvm82hF7 zFJkX;s|;VpIY_wjy**ZvOAl7Tqy24hc7hQcn0JDyz#MGH4x5)+idNgjL^aq{wdo}d z5FMI?E5SkXxd$eDoIeEeb~upP@LM4($Q|={Z=dImDJI?4yCFhWcIN?8K5{O;Tugm% zAyM<1^sLEyTU6S&7v{~1!~I*)(gOMFgXAz`L@`6XRGHBp)7%q^U37SVsah{i@oLkb z$SZ1ld*eCMpSyMKz%L7gFPqQ=%C2*nTO|v~7jV7FH!usi;bvnST5uD9RH{D*g{LV@ zm8{nT_u-yC-1AMl>ts<}0KWu*1xu+!1E!|*!p+!7t*UZ4DTMTb2P z$~oCy5qllzkiP;1RMKJ)8)lbT$E#uGoy^}aK>Ug5zRHlmxHO@@S%SN;H$oHi?pBLEJ`sz>Rff@q3JLH(P3<_*Qjov-`S^mr zPwzA`r6AFH@dH%Djg$bi60_m`kCQ=HYr!w=KJq2kEYYTd5)t{DZqK)6M!Gwpc5l*E%WWS?#V_$8uhPb%y9As2NH*NhT;nDW zKU>;^84f#VTMr?k!k^G0RhMwq&uAi$h75eVgAl6^OqYX^r3X}~=Ll=2mnChl@AKK8 zN5S3+v&!oa4Fz=WW8tg`PI+7$e-Mlk9Vet>3NMAl|AC=C?Ul3Xru0;Ge?hz@;*7`Y zlO&w4)DF#SKfzo0%a>g9wzg{_T8qsh>TXc$EnP+Q2av?sb{nJQl=6@paSt~CyF##( zQzsn(AQ|T&)74P3rVLt@Cc^jgj)Z?2j_L5SnNYmp8kbjLa3a2|$m;073XK{UHMiv| zdZT4d5u6P&RicfR9lEwY=xVa|qUOi_c^N9?Q#Yz0sK1EVdXF%3S#cqwT|Wixo{zIa zGSjUtombx}B?|d=jH`54y?!zmE0yS^+=)<@*UGyZ9#_ZAaxv6OsiV%@<8pW{!XY6C zv?*AaM@BkbO{Xe7x1Y^5fKB*)sfM)}-Gj8lc6V{c-t3g_K-blVK4h%r9pO+%hAPF) zPhXHnk%zQwo#>od#&GgzJGC9iA z#`KRrcuv)DW%z@V?{69Q^`Sv#syrELMJ%1B(4 z-hk7(eP-*4lE5Njh1-+%$q%h4rycb<1>d6?scTShDI}we0OY9}|E{k2*{cqB~(ezdsbzM$G~U@I)(FkDD*-HotM^|KsS(!M47!K_hn#OI!#`}?556UgS?>X4`5+&&uB^(4p3+&b&T@cj| zQPP7Zq;6j=xZE_-moX=$Buy}5av}RXF^U*^K&m&(Y;_EUi3ja}F{Db*)-HrG+9G#sK%{sED*-c60vzHN zg}+N2J7RkFy#>?{FvOm!h&_A?9Cr7K%ey(6XT8`L{N$@vJudEY_~jBppO@-dse+s|JggAGwxtt-&4%g$)qj)gm?P zOgpxHDk_t}D~ji#1c_AC6ZldE%fOlq)#%G|;R6Y*+g3B%1l`vBDhQhFI+OsNXu9Y( zK5tc1evmlaU-!_g8L%PZc0@>F53}yoFn@}Oj-1IpE;_?L^I#NpqRv=N^iSO2-TifX zk5xE@+^$QcFIhgmkcQLy|8|3SDWTJyxaNP!JZ47N;nX5*7mmL`7!E2xm--u&fpehD zS>f@;=T=v-!(H+2xq8KI4O&#^hLI zbK;^mjVSX2rG|IZAq%X#I8eq>-+L^Hl7vkFOYjkPZ$&1dmM6s=W_E&mDA4P!RgVKc zQ@`wS+4<-ZGf1XCG#lP@Yx5OvMqh7R$K*{B`)e57XWwfIZi2q3=`YQCTJ1R4?CcO4 zeQ~b$i*2ucEGFWaYbT*J67`X;(Sd<8fef_yc19RXLRyfjCH$X0%|?%~B%|LJ$R4Bk zRncjh1F+5qoT~X?;(}YzBTl>R)r9;_b&HhHD&>H<(0$ZWwCVc3e?BTeZ*w%J z86{2uK{3O`4X|ffxezAfuQWY#Fset6UG*co>_3y+8kDE;yW^DmGk2Tu!w=g?v#nqh zyqSH7%%I()5u+CX44SC{NxM<^E`kj-Z9A_-Vad;Y3{Mfw=33faY%jmpY1KqL3*Gn@ zYBE3-toD!+AcNX*nFI?7-K|Q=U+xk0Kj{y&N2#y;`XAdGWvNiop!eX8>V!+wA@1%? z^f-ktwu!AysThtyN{f;4X$ft~2!30W_^sf8b}AoMFBTTF9cMH7sk$hts?)wmC?SvH z8(T%7nj`6bXwTGJ?hyEa^%6;~5x>iEDqrdD9`vwR`bFt6IQ8Nj={%XO zUEOHUW@ko35kU?&b%Z!f-FuGi3WfvekEKg*1glql@hEH$rzavcitt6wf#~3eMY#LR zJasUTV)bs|+>!#0a!z~*n~U!%7!HgUjmaL^wUIe*4smwzs_JrT?#hSPL(|jz?e!a} zVEvSUecr&E-lwxCn0611tkAam^K_SCBsSCSv|gR$?A|OU&IFWoS*)<@mWVINjRkQr zco(Wu)8%UnPb5%Ff#FpAQ`#X3QH!B|(%OeG-#+VJ9JEq~kV%$fLQmd0|)XoL;6 z8v+pp>x6HATjVQ9V-!Y$CaP){72df*uXsau1yNy$DbeJn%@-&exB}Qwj4neN6e%m__-CfN1TdC>|Kkcm63jAm;GB5N5FkcI{rNFCT zxm6O=^fuJ(OzxanOCqP?57&Fl#xrAMIjMmaGcxH3?I)v2A-iA9%Tf-TLKeo&lWj*s zeMY^tSAyc8*eIu7d<`#3)GYE5Q~Tgmz0LU+{c2y6I_a6!aEgrvlFSziXx*(*PsLCX z7v{UoOLg71d|D{Cjd1dl@m%CDq+a95q3Vw+cKq;R`F2|Pm@YQIn_YFb3FA$86i`-g zE}}hc7_nL3ikp8S>%IY$(Ab!u${Ol@>c+_AxCUhHl^$V_8zwxPWT3u5qw0PTm?sX2 zWM5HsBpLR4OWmGJnvGz=$!xFLkrDZk#ZY~UL;CtD%9iq~vW_{kUg4O4XQc02pSIYvn4a$oa$w}z|7;hR42#wi($*^AWlrYE9~J(YDWBtf=wzq| zu$Wf=nBy^q2Z;ru7uVADtYk(U(gUG+dhH6GbYkBHd+3^jeyH!QTOl- z#B9XoPC+xXK~{1ufZAWRsrK;7{9`qv|Mvz+5o3f4`P^1@k}rthmtoQ3d(o$jU0!cn ztXVtHSyR=E1#;jnVC@jU8^uGyFUvW1u#dZotb`*+_!-Npt2usDi0|H%jWVQv;9}RM zEZI;J6l=b}E%oaSjwHk6@`07^C!_Ahr}#}L9~X#G5#f&rK`VK{#qu-=0oo}LW(03z z8)%g>p zQXdIvRxDfV?ul+{ld8`_Nd%uJCtbDW?WZ>DsUuZaKB4N~^40_`@96R{&s!sfD3tL( zZH<|HV2Lst!hK`9{J|^o2-1s4Bh#MI4*;rCE3$1wfMjWkve%O{wbBb^y>|Dnvfd?1 zU=m0z_+jGX#IJU(GJRI27Hnx4y?JmKQ5Vs|un%DvX&)*b!D26b?RY*b%lzJRLdH0 zXSPM%Uz%|zYQML;pNCo(8lmaq%1vKjLxCe2_zMOA^+O=sTt5QUA z5d1Wx4FRS?6jA_^Y;-^pg{9V40Dis+_d4GVih69c?y5cpl!r-cKkS%emN_jiS!xEcUg?g}3C&$MI*oqOZ7h6U=AY zVf%KUPC#adn2E6;AutTfe@u<0z0%y4^gKB*9ffBQb(4lSI`K#|7`J|>ct2#pYN(98 zdtt%A!IldzaLO$jaT}1v+V8Rqf$vkmP+Q!4HT{PpHw@+2b;H@445Kt*#Q9o9+eFKAQ&=fFEmRGmt-nX^ZxAx;S?BZVQikpD~#1uj3E^8)GV z;yY)warr~^{hg+%U2WB=%eX4HC^*!5dAj8UK}g-0_$$_;HL=Be79TnNsXAMgqGajSy)5vY3eKS30l z=BUiIEvjpvXha}R=EttO=M-w5Kk_nSyCrG1aE2%xM_QY<)I@0-)+cfP)U4r@BG;y= zLDc}WWdO|<<~LF`{{Buy(V!p?AhqWUvsd8A#%)K_C-=vMU)S7x-+)T(AQxbR5e}x} zOwCW1Qr(_nU09d9jV<`5KJ?OXb~SLl=CZJ@ospz_vFY4wX9RY4-Ez3u<4hlU*%>D#LroJXQY8dg*=au$GKE3{D;L z5oAH;pJOfdK?M>}e`7!;-aW#(mt(4&e3k9`+Neg@ZyiA-&QU{PKnTgnVflU9z69U7 zoo(~d(^Y}feEY_)7KW}z9pP!+#+aH6X-#UyEcR^>+vHU2{KK_U%{-Je-lhB`)W_`^ zO3kKTF%+KFapJ)M<+d}xMrGXX{eHP9j@)lH7at!041r&&1tFJU?&cdX;Y3rK(ZW?`w<%dnZ^KG z7~+|AcNK@X#&BF>yQfgK^Qs1uf3f~z;A&Ica@k%llit<<@&J`>iC^2(2iz&)7kWo1 z6G{z2Lm;||Hq1((9hCmxw0)IO^(FcchDy0&_mLyzC^13(FqlBCMYR-K2nD*dV!^MsW`f2*T3z$kmm# zS4C@mxOdyLW+>3}fE8PquKjo*e-I`1ZS@4&5!_aUc%3SIsD?g8eic?*bwt9SHxG{!^BpT`qu$j z@Ev{>+bOw?gl~JzvnbsFtawl8ZkIrJy`Zlu-gp77Sn4~~>7I(hmyE7wzJyjpH<3*J zO=imnoR!~V(Qk6x=5SM7kQcMTm|W0D_fS@{4%Gz(gxZ1f0rKI(Ss0M<02;Om1Bu7n zVVnCtPLf}T{-rb?oTxI&+L7tUrq%-O)&?7l?#jfa#mEVZ`~<_{@ik!*l5Z!XVzK2Oh}eUXCqp6KEgc*+}kp%kLK zMe)3SVg&2EiBXYweH9D^X7?~32+Z9Sr6Hnq10Wv|cM-~rpi!^TwoM$yNTF)h5<(EAMS2Xo<&`T;eb%s}lU&fq$M8lvX|S_E z*{R|Y%bpnI`sE=gM8}KoG!oZTwD9a&2SOcSY~q)0=kK7lS-RPVYqc>fQTNZ*@$8Na zMjkntW8YaMcM2Uz+D#mP_pRC$kO_So6hXg}^QYUJ?Q)m_Mvz`8kg#X!Bb;5a4ZH_K z0d3OsE9SKmX3d8E=YXQA9890?%}gGjs6&CdV>ob_U+YbrggNER-);LMch~R8-lfaw zA>R3=y<=yJ>S8TaFC3x}-b}chY^#uMwX<{%Z;B$;0G%s7)%~B32<`fUQr4H#4$ONr zC*Qb9q`8@i+=QXTBYk-R-y4d#K~6&)>5~st;qlK!r|w`V+9~cB_p?uFx>P5slyP#W z#&zdUohQwgS&SZMamZcb!)Z(nnYmqd7&PSw;GIDcH`0IV96sd~*73{N&r%s@KUD zbD1=C1v|}ra_2@P$KAo|Tr%x4R7!zmf#`oD#xF|0G!8h1=*+`?fJ5%A*=*{!nbW z_mx+{QS$gqpO)Umw8&WKM$O>>mOB!E+#D;ogB6}qnmeWyc+ve!|;cHjA znEnDxpE|JQ{=;>|KW@%}H2;Sfz)pj0>=dj3!@~QC(H?z2GRf617KImo*%ov;U{Th75&aV=u+Zq)lrte zia5>>QW^fhqjQ!`gq=`m_hEaO=R2P!P_^z>NGT7Q%Bp(9^F!393l!>ip+>Xphg5H! zQlus=vA12Jm*ydV&CD(6{hT=tv!U#6W+maz+AeGz{j_3?a!|{|9>hKKt4mMeMBY{! zQrf5*-$UY-m7;6aNUg{u*k1VQNY;6U_|6<-AU^z=2PRd7p-VHdQf37!k@0y#YvY-Q zXUH?w+#!zYi+ixzvJ}lolf~m+X*m57o9qcg;Vj8mykcmskL*AF3knNtSJ z{p2Uwz{WI6(E8S~woQ!%F{=PRCP}3D;u@)SB`L4nle~chnPa6gi$uQUx5Zs7S2Sm@%Qfo1nhcnoxB4J8D-I62 z!1l{RFW`hWSF7;k;^()*DJN7O#M7xNigHtxTBv?e!*~=D`ftwcxieZ24SRQe-ib2` z#`BoBP(l7~M83)`M!8yM>Iq7GK}sKZtJ^ILwIr~D`Vu%w-xJIDMN~te1ZtnNYMO2q z#!6ky?;@syI$wF_Ow8}t+r`sHts_3d%A!Ey3MXO1W;RTA)8Z!m2ZF)n zIuN8m%^=8acDfQ1DD!YotGCdf%^@Y+v=;0WGzAEXAHxTF@aq9TOoLkY%oF9AqV6!v zc$ym09y#^2`4azIBRrS;a>NSPDZyf!e5~z-#^3yb&1xX2EEBz=W zzk6hv4O7~W4?({#b-Q8;o)h?CW_&nxos)1=$dDC48^>rHd<|I!=`gQNb>rh#B#C&c zT`$~thnFE&?Q^nNJE{LV=UU;~G0&F0sT7^?*2%OBXyE+SE@6+a;m!P_2f-tjw#XUu z!Bl?(UqehbKn3+@8`m`mr(YzYGJ(tb-@GD!&eh{U;bh~ws=&3`T(-R&VkPx#G}A8) zbvHz1UBOCm%Yhe`wv$RgE*AnXZ8W89e(~@kvbNP6_K8SCi1=XMn!!CeojD18_I7&W z{l+fA&gfE+EJ{L)+$t;!`zH0oE}pw~E9w!vZC#04x*lvsg7F^&{>9lLxaDTv?wPt*YnRKT^RF zUaC!MZMl)hY)OMYOK^xWU9;AuJ}SqQkA8*BTwO`u)AM?lK<)?FW?kgiV9t?AMsVJR z$Su&a0Tw~uwO--)1aUFiG7X=!T;3Bwm#b;z8c~PvPG$us5#rLI&zmimD^i~dPUCX<-`6|&ITdw8t4p&nT) zw@bdfWeGoc3@b$}fgwA_JEDjnDqh+pz0@DUsp)5R3`8Ov&$L&NJH-tD$GthmrSJk~ zSW6Hy`ancr{plA+rtTf{WLLvtu=-c+u2Inj`U$0|vB>d+ioc8YRUCw~4EE<=&{f}% z-_)>@XD1Zz4_zQ5N|IZF?icT1{KEV!XXubr3H8_1VFUX1UM7?8%>{@C`zCekA0<#4v0GmvF{Q*|lG;)P9C_so0mlZ& zaF1`a@Fu7+8%7Oqz&1tHFq7rx+PFZF)V8Sz+QxWf#$RFBl58h*LwwRD(L8zjU7-HN z@-E*7No7@mcUv4(K;70knmHrt41rb)=e7D`&R#GO&*LohrniIbL>l&G(K<&CK>B+a zDnnvL)ZVCH44EhB1DQG`=*GF~(fOff-3#HMf#1X!;~aL2&TytvO0OGS+7zNg7t5-EUsU)MMEr0E*u@jVvq{zMY@HS%hey% zS`_LXl*D;{8-8}mLSO!JKxO{MfPAezV&s*XftOSqM?#KLQ*sWJ0q}SCz@&%RN%~pz z9Z}lcex!_QMMsqD09Z8fydEC39GJkpQntPZMOI%sup z$~<$sC2g^GhBf$#>Io()&<)O5OpJUnP#WoVX_`qI|yeJ!781zAuc8fNDZHZia#kEIIE(Bn^ z$w(?WL|lB=pEmYPc%64wjo<}arm-E>Ow1znm^#@J%bs9OkkILBQeRgyM^Q@H)G)%* zt(vB6|K}rDL1mJ>xsp!|MCDRC>&@2%3*pSUysv)HJ7@Wn)@JU$0RuRAcCAP3$*(9| zfbK!C2*LLgc61^Yk-GuROvj3yrBY;=*M*ZsAZiF8Y^;7y9>ksCN9L_N3 zNBnxH{m{xcikl=&yo?2?I{7~hjvxmF=M@??x2fnG(Xnp6@Az618=KQz#Z@)PUzStU zpWyx{wS5ZRX6X?xbv?MYdna ze?OnAB;>;14K-@SNa|ya)XN63+^GutLML`nUS;4E#YMmOL!-7a?g0Y;!H(tJx=Wd2<=9zV8aHKw3VZ)F~hyJ|GgNhyx`XdoUFfE0)Y9~GC+P6A5$VNw> zTK1hqExjbzdLQqh>&q#3Ae+5_=PXQr@GW0UR<6>-p0cOjfJRstIYs@~+^!BieiJ)w zqG_U~bP^y*pP_S%J-ycRVV4YI{hz$Q_gph+HTKorh>n2wCC}MC34F!0(=Y21LfmPV zm>Kl+v-WSZrfCmMoRqKYMuf9-7v{H9aRaTN)VqcNtl9@TGMEda*XxX3%-6B3#Ko*O z7r&PayE;tE4exKGREnba6>#X`P_kc^a0h7i6)&+ zcmID21m3LD^RC%EXCK|OM<^R@3ZING)SNlNk(Zt?@^yRJv1Bv1eYc=Rwq;!9RFfq$ zV)E>464PAc#w6~>iGIi*?h_VoIIqr|cbmesUFl6@$^NbmbguO-jUPXuI8C`4y@DRs zK=l9RajG6WA1d*GA58=!uTue^KK`%thPP)#W{k_ff+Q_EMjA@ z1W5+{0q>X&s%vl#s6nVAvGJSTuze@zHC~y82pc})Om-35t+l_H;BGVYUgt>>Tf&V$ z;pAqo-|O3-TiY|rZmoe@;VJQU*|>5n^EHGwU&gdQ5hI2|T_F(`Y2(f*inG-Hh>RK< zgT7qh56il!7oOdUBLxt`6T9@J{13#9qc84H*j8rCJQRBabQ#Zpdtog;Y7F}uz$&APZ$LN3^(vZX^$!e{^;F5~I4UdRdGcwme^t#&j<@2|BmUI$e3*^5O%* z_+=_>3Hh)Nfmo7RD(|Ga_AVc)JXH+%b=Ph8|3MtYH&tV1+x# zuV*L??%i&_aETHSUx9jl$TZ0s=6o7dc}C|`$EP}h`=5Z6+10{3E}+hGr(^o~Jn7^k zm(yMPJ5BMc!E8P5Om~HRE+ljp8a6=c7f21$%6~q>xzJ+l*=F&Z{-8&6VjJ|%wH@@` zT#wCM__8)t=RX82S`ov>=ko?$buAY;8q#XDD)eadomUROO4g=7+3!A%G&j+wo=i!& zi51C?o^=U9v^{L6=&O&#N;Z$N2|z1>R-Q*wW!IpyA`RGmCY-5=z)K`elRpJ?hFwBUeVj^$02YoH zM{*@G`+AWFi)d@>5kVW;&uBG8G(GXX)Ys>yx|Vr|45X*r#=gvRW*!@Z+uwUkhDgNo zd}sVJ%@8r5-=sqBGj;}>nD(020rvI4>ndl)G?~~30*bQGd`=?I$#FRTP*A?Ykp1FT za3)V*mP#8rIS#kr$4ufK{UvqwaXDsIf-PB1f4IE!G^1FNv|O=c zXmeLNuVg65hcgc|lPH0EZL(CVt86$Qfu4XB`V+{=SKwtvQO#c`-+mBf){H_E{^K5S z90)yVaBuQSo=eXkA53m62;h3V+sm!3Z_}Y>@AK&>2Yp8{-<_XO&%cvBBiyp;}ZCMleGk3HXrK+ z)sufddOd{e4x{5>=j1leLVY{;HWr8?3WpwT^JvS#?ZnkUgE5jNwYtwl=eYCU1Kuq} z(ZZH%iqK{-oOF(DC1=e_o{&t91SgT^SxyYzkWh5}T#otOK;muRKK=9)!s|(LuKt_O z5$1`y4*JzK@K6liWjCKR(>+M7CxYG@BHtg@dok(EI64 z?l$TO=|HEq?gCLc_Z*_li>hiWJKmzv%6x&gYKBcXC5caNs(OSck2p%_F4k!vP>mXPjzTEjC*}+e>cnYo#<9Gg8K%gM=z-Hv=f+*( zYGaWhVDUKc8NpcQh_0)^W#FjO^WLglgHh@pM#I3-L*J-`;eHgTBk|X2GAAnVORwur zx&9S#4gYVCI$TARkMs_WU>a?HeYR-tIGcoWR9%6Zng1#@%hPIJ0{P}t&94s0{PwnZ ztT>JaQefls%9|v~e`1{GW2$p-GyM_2yQ9vnH419<28jsf6!=8ICPiuRX4P5F+27E?XotZw-!E zI&?`Hz|rrD6#)L?<9^e!MJ?3@))l&buTXPF>MqYaTarNt4&7@cpc*1jsisxD5vxh^ zAdFJPxuvBB@w~7HisTtZ@z*1XCiVHT&ZJk-Y2PwUOU^OOV^{rL?w)+*yV|-$npTtX z*({^Qpa#Ag*h?hW#pkeTq}H@ zsZ|3;uoU@e4fX$mrHW+z>8uM-L!7s+e(D4{psP_ji_}rGM*hTJvr2TFkJ(dRX}U*! z(Sg2Lvz9EAYJY39Qs=6{g|zi>*R@HWL%V*JAzw|>9<$onJAb7jbwm%ut7p-xUzv~^ z`pbPe4%>sAE=_<8>7EB@rW%(#it1&I|`&3pi8$O^_to`^xL;;m$O6L0V& zxTKAIq8s{J$$(S6YjYtK&Q`{P@h2WwTR5m;@YmyKXB4mHXX`Sz2rRUz&2t5KeR)^8 z8f9Vnib*vaQHGa0n-2y3QC$Wp;)Mpf4{RFwYapJUW970vrON6L4Z~H`oxh5#KhB)x zSQp4hCc(s@a@35KFdJCKF{nWSQ~WyX<&w>Y=qtxyu0k*Sd#OSZb(VF!iyr_|iAeK! z)qpi$x|DOvFg;8VPtuR7h`mi_-H>{vr_<45(tnpz)_15-(cs}Lra9a0p~2_0_eK%z zalqfd>4=aI`uiRGB&!9h*NdnQt>{$Y@30MgRcVo25d%*ngMHw<@N>O=uhV&6e4+%u ze0{+kD?W%BZpkc`-jmDk(gmY6FR(v#BPs`2?^xepco@p{2e{J@oT7BsmU4%!%suc& z#RuWY?OMlXfI{O#z~%Ke{>99o{06(hj3oQ4P%fsr2(r-djBf3j;CrmgEr>2eL)@S$ z6>u~Vl{l@}Q1z0M9^ke5!ab)085*6f>hysEm-VwBx*Tv@gF6}mxo%vB`rC1sD!eZU zn;%23+8;okFYwD#s|_3GMU;iBEX*m47|mG}p&z7kh26sbp~$gA)ERmWhJc(8V?Hi# z;e|gE!r+LoJPuyg6T-0zoRyY7-lJ8KP{#j&7R_EfTGA~2z^(Z!9 zrl$?h*)+$l@wuJ%6|t86*3FXl$p2Ux#oqe-Zk{ zNN|9}!G9a8E`r#kd@x4f2X|bhNPiO@cbYX~)7V$;`x_!VYcW3;wt^tB^qZ!l7+caP znKWB4gcrTdsN;)_uz{`6Qr2EK>7?roZ#}}g&{ZC_*gFUoSlR6PLbdQcIFnbFCv+}5 z+oH#3R+eI)w84*WI;LoCAVg)G6xwH*@rBNSFPy-F6T7~zQVwzL=8Fz?xIY8q1_0u- zh~sSRh~J+K(QjjD;Oj)@{uNi0A3UHa$XAkP|}~ zTVHlR1+!j`gB9?OZQw)o(pVEb-`eg7p~Ui)18l*spc)hGveSq?=4@JhRR^y!JRmM6 z;Ns;UDD|juv;$oGf~}8;YnMX3V1(&W*)vhTFpeI3fh>p+jTBu{gDt5n-loZisAgry z*gRNyC#SJ?=GAlsH^Iq5_V=Z(^6cRG?LwTZ(LAJ=c`0MEZ$@J|hr1_S?R0abEsE3~ z7B;&ggWT(O(+I?UGu-YrU7Bgtk$i1=E*tf>gV&hvcz;s|TI-=2mCk(*JmA;WhpIN` zUYWQE&Y0{^1k&LX0$MG#h_X|e!Wu@8R2YYxWu7dlLa`e?IwE>rt0HN$M}q_wF;Ynl zF;ng1bj#4@L2Nm>~ZPb5h{%^ILK|D;yE+Zy(tB1?lBk)|KwF z!5gAeReqfnGbBsDRGV^(bnK7OTcJ`TjOj;yZS!vkKVQjHoS^nH0WZ0Msb1m2c%1$R zNMyo<{0_TNYgI$+{2kd5ewG~9r~3smb1PELYb~*yeD0;L`K_CJ1JqU?nA~|fQ|cSk z<=?6%r>u270|K8RH%`vO@NUCe{9nr+>G?UiPlGpzeoziVG2;~)u9yajEn_S4pB6Q7 z!<5m(c&@?dvj2ckNhYI*r?HRA?K7=~h0{J}Rr0Z}imjoZarMY{|zbKD}yR05+^@&fz%-VKkc0+ z3T%cNhkNuyI9pS5P85S$z&{_YGo<&-AlKXJoTdH8urjR1jGhwc$#uFkz$-{b25+fm zZ{=+5k{^s;)e7qfQv0`{6oY(n+hU}t`Cf$FS|Ue7TG?-F;P{3XZp1b_=VXo4o|wx` zm|s4^Alajw_b;9?oRIoW%GGn*iXYk)L#Q-aPRYg^z_H3RpStPo&q1SvS8wRyJ;LzZ zDSP6AE?gzf)E`wQ!*e&7t0gq8${=&Y=4e=F>U(efi7uhc|Dc0YhV(`!)PT{IY4cJ~3$VUEv)WYDPx(4mjWR4`Ofw<p5GMs~*^xD<rKrTp)6mXQS2YQ{mAiP(P_)nOwIG9y*+uQ_yV)^c|Uea*N!YHX6nI33HT$bVWaFE}WdB1d6_1 zDvlfeSzwB_)pj7|*Ah{eYVd1UZ>#b5!S9Gp4HA|!no;49SzP(coP=!~@(#jGDc64;yOt}tw7?g_wCDeL_^j8aQP?4&`9 zncHigSENn7j&#z06HeuaV>^2)a9?QC>M6VGm~HIIE-o;kg4XVJU4QAOZDKAXpk(m~ zcjIu0Z8Ck6j_vY6_+RPfgYkF}>IDVxHNwD}RF4hd<6wG#{D!l^dNCe9y6S$>3t`;T z7-1;PUA%=FOO6tEKU9xbezASfp=&ntShIW=Oj>f{3R%jrl7`XM!V-^_mD+1OXW*32 z*s5yM31yz=bMf~zLZ(T;f zIDL%{3X#7GJ3*CY#(7o!pF^#Ql}Yn&K3S|Uv_A6_M__TSsJxod zACT+MP`#~2A^T{WMHkbe%iOzj%QMv1BXM(|aZoSK?i~+>Almy3rtceg>l=*aX;JFv z)Wa)qEwNT1>H~YTtS3M!g{*^RT4*fge**rh#dbB+Gc>w%a4nV*AZ`A}ZWAAZ;Z zagjIlU73MhJOh?HDeq`DXETk-CsL^grk(d(O_g6Zv?-B)k)P`+T5pA1?cWvgK^}3K z@ih{BY)5QLS(LqeafVY@YRcQwi*43|c#|Mo78m+WP-x_5!iq3HaMfmikV}4%7eP>F zQf&Wk{y6=00<$p0WP7)8WJhV|wXQ|hmwq6s-E1QVkbxBi%!pBAA{zJFD5_@NL)<;< z8{?=0*gJMi(N~Q)vNlCaI@OaGz_j>*^^?-hu_VncKRU+|7BjXzo(H5&3zM8`9B{q z_?7@1E2Rzb)YGNa2@BheFH=ii;j_n^EkqRpnr7zt({;%t`s@6|=YE|3Q@^>ao9A?P z7!4A%?2R=7gIlnh#sL{u_!lA&^Bs*V^9&CP;%gk^3Zcsj%Yv`w97j!{JIh2{q8plo zeO0kb()$rQ&%?VquBk?oi371RLCZ}ABDF4y1Lk-!1K}Jk{tCi#IFS@k%q3Hb5q)*fxr2NIwR;yzDz=v_&Y@ztC%O-dOdv=j9 z`gNOS7pGg$+BXTGo&4RCR<$E>30%ERPfjjM(h{{u=Y~OQ!(*s-Nq*JFD<`M6Z+- z>BXU#hy8x;*dIjodPE4Geyc-gC$tZWf^CuOzCr4JCpe3p<2kiOx2SU;=v$xldti59 zR}ECUg!T#FY}rGs?v*bR_Z0j_=B_(^?Tpq}w$+BPeX3V%3znD^6d8gKOU!v5y-wcJ z0q9pTFo2j9*Y%d8xQ$aQ+qsMPN5OejoAA~J7%5X|BX9LqrZyAxdCX{ETI+bWDsx+V zx7}L&ckoRrLSyk21Fj+JXlUR#NskEA; zTjk5q-P_@c@pi3ZOP&Ou>$LPL<*3w0ILsQex|}RSS|LLNbqk{16p8fRzRieymkkQ$ z(v)gcSRU;2>yV#-Y_Nr3o!%E@ONp)zaktzJ^m@@(?2RxW#Vf^AM_h5@caKZX@440K zD!#fEW(apn{NC(K(xo5d*j((jUivVCnzI5Yf+YS`E62E0b+&0lYoLmZUm)e3XBIuiQhozg5Yx<+i?_kiHpK4Rq0xzl%&I+^>Kbl1dthzxD zxS6wG9nZ30u-&M*r!YW`RL-qm`GJ|-e`=SCDHn1l1!L9ri@8Y zQ?@$LfsKfO*u7#IcwWgrX<76YVvN?43%^4=Oh11Upf zRQAgKZI&CD)9kv<__i9QN@hc4s1s0B6mun2z41?>PR>Z>o8#(5jtH=!Tr$3-vFZ2r;!l{To zF*jp^R^(QFmTHB}QVQrhQiHmoW+Y{}KY%QhlhV^XMOcRhOyq?Z1@9YdRr6L(<5NqD zIdLY&e7oVPGi^HVH@<6k-Qy#%9HQR8r)W|7Z~Y;~lONh91|)T_3w8)+G;N;PI|=^I zoKxsCE$j6LV7>1ecBCEnY#d!q77d*U>BP+SJ6>uFz+AdC`j#9s*Km{upnQ!(16kr{ zGw1dMn>^7;KN4u*C}!&a`KShi4l5(`=Qd5TFFbwTwRE4b$CujVZdCccw;vd&#HD-k z4=q=Q+YsGwR(nS#tn@i1bE6!rW*c1741Ws;3z2o^e15MTek&-To9Cjn7vX#+_P8iN zRjKbNkULIBp-+&&DH8~F)Nt4f*>=jOIcZv|4{ zT3@(18$DvF&@fAB)Rp09%bL#KD!oOHDf2t*uS&6v)j^{DTl6b0h8&Q`jkd3Q8sdHM zF=M0qIkWsL6^Du_{ zZ&zOylZwI}bABxJut?CmMHPDcAdPt!*#@c}eZS)J@d+jA$<#uObg{P@^&k*81qu7W zs~D91;VZUV(q2g_#@Yuz)bQr{-{oQR$Z|AO8$i+&F7RK)o$#IOdan(MJNbBA`v=yR zIZx6}SsgQg8B~oOt`cc=m|WUky)$#0&V+P*<8fv(-InW-^Kd2FO^UP* z^D@PlTj{1ei94tcy_e8V_1>xA<@)cyONH{K$%A2vlaG!`0 z=;O?!fI&qWJ#e}|7e<^M>@9cle%3NJ_`VtK50w>f#&1RH|Hc|hU#jv^!c*8-S`B)E ztr zCh6g5g-9DW3noVPQ32dwqQqoRH^5&fp-<#E(sVM;ocKG%X#K5diSez83B2X0jyVK@ zpB}pn*V%3uc`0+w$KPEfj!R$OHd(7ACLWY(UF^2QmX4L}xe7E?qrN*t?Hi$G#m5eE z=kjj8@GxWtaAPh=r-yry@$7oYPoFDEjYD7aQL~Jsbu1&MpaDv0F?GgdvE!&fo0luK!1!7n_9ByZMDYgM7Y=ymv}}SrW#>^J37xL<{5I` zr^P~Imi2aFg37*Zp&-8%>_?plpKC8Yn>zFhl(|!C!nHiS;ZVN{Zq@nr=+;I_LW#Y4 zO%x;Sk(yUdbp@sgba?%qGnvM96RbmNc>NvIehgUWPBSfSw#$sJwAma6(a3S(jMh2^ zlym%|p9hsoKWQ*<;-AMG_5i^iqrQ)T0`X6$D~i!JZT2$&YvIz}tD4sg!BuW0+D@QL zebHGX&Gxr^Th}EO!k-n5Q5U)li7m=?OqquX{!?#C+Zvy1)up6z38s1*jZt$dxDU7& zvOm;yj9uQt7_O4x6A(r6jKm}T*Y>8TE#m_s2z~B_bXTzxURF@NH#fm*mpjyUy2+TT zahRu^t}5#;|4>2IMFF)Jks|PqGG3CB9mdBT*y`k}H0y`YecforeCooxm;071Jh>$~ z0xt6?*8U+EHSwIBj>2+I$-QT-26G9DMb> z$wvN7F>geZa8+r3XCygxLOypkK5G`EqQX}`n>n9@y8kJsW4{kIV0U7$hanJSb`4%M zge4Yu-iz^@S>{ixjs`l*LXJ4u7aZfd*=L1MyfR(cShZR&2u>P3mOptP+ZmlhU51~u zLi$Om<#u)E#8v$;9^Mab3Ob;}{H{&<=cB8!lX`FEA=$fyAe&2>{-if)BFKa(!kaTb z=O(#-_U>IM7@tqGnp&>XTk-mPRc>_#d7=O^$de$b%H5L*t^<3J0Snzsi&Otj_@!%s zzt=m~6`9o9Zw5o0bhEleK*hEa^aqjat}%8`vrUICJVL8CwyluZGX>3slt-LNzi67l z9=nXZg4*v^?ONREW6H<;GNlnSl+YsM<&Yo%itJw$`JSy(lGPE&LN6%6>lu~8k*)0` z-Tc7KMS<%$;il9;D35Y(3V`ZF!g=-QRO0t7m#Tko4#N+)Hs&1C?vDC>Xhp`g{yQ36 zpPFtU$UZ7e$A8Jcglp*MJJO!%B-oS^}OR!PB=FbU|@& zS* zB2jn~Sf{c7zoTmbXL|qt=XX1ut~*_%lI?W5sKh$uQZC!S97&EGU98;p>mng7A;#=` z&Z!914h~Mlj^viuaZ8x3LPA;$%Us6XGR9`?V%xX>+wbXl>Zu-M`+h#}%j^Amzg`Q$ zCSt?8fP(vdyvAu(ejbA`k_=Vk1Art(eHRlCJ@i{e zOj_<3@;O{mO9z!7S4=wk?1ZAk!L4G+WT+w+1d1HDQqGexwDbDgQ0RU0p*X-o0I$FX zKXi3$rBYFJ?4$axTecT3j7OXf=os`RtW&!j) zj<^K+=E#J>!w49&LrD;nf^X(cxu3Pob}Tvgns8X{fBYAN4{jS8zic$I0x3A4siU2`&iNfqvq4;>4q)R=L?cZ(l7My z)Z5<}a{FxFDOfW*5nIQ&llsO0w2>3+r6t|bMG$g>^IYNc6Wk30&7yObMyx@f7X2qg zRC*d+>yRH$a~wOb&iv`iS01w{OVvr~+sISW^=A~7+JlC1*NNemVDrgDPeAA#SU}hu zR|BothlUZS2D6KbH?o1A5U9J8PNn)$&_*WOquF!NWkgy z0|Dtw`473+&cHo^QNba0+2Bg%rHx5 zl|ZQ~YHISRLVaS#wh&&({4T z4KtG2ZgTo%E#qu-mdA#1EkNNa@Tv*rU1F25xlEnad{$`_xHFS5M)rG{mco z7<-)~uzo~PBec{J!F&7XqlL8NQ;Ux^ha~~)@2c^ukaBLLG}OK8LKpjpOsiTe3M`{b zM<8FBy+CfVr<56d7U5uI%3HdL%s4;qnR=yDt>QbV71Gug$fuVUJ?njRP8FaRJV0*1 z?yp3<1(u8f9&D+}DPVwpkrOCm-VevzjYzqAV9+&UDCQDMEUDBm_1KLivV~a;GGaI* z@fgi5nk0YA`JqL|dPQFasRitE(6zJQ24wqmWuI`4!Ks$OR|9p(IC2e^IUCY%w26&~ zg9PBdvmH+94uZcd%T4u9hr!wSMQbJZwfW$) zuFrEKgmz@_DyTo)Hh7be%GZ&e1&O}q7&%Y4nmuT&j(S);hVV8ikEM=gU~9w}+i3yk zCzxh^16q-()5H~aYsFl(2YJOzSf-1;M~_GqQ5%t^<;@oX@Q1t#YO-@3p4~v(DPY$} zpG0|_m#Jt|D1Nbyq3mQU<=t1i1Os(;I(kSViaUte7?kn0jEbfND360@7~m{*+*K0M zB^fU6`Xzl=?cMhIY=3Rtb{4*CXBV92Zvq9?fQ7|8Bs2Akv*->_?|_XN*c9|x^P5GR zV{)LJbj6Rm_^$T+x#*;YZ(I_4yLJD35O=wrG4#Gi1bNz7U`hM|it&p!ke<ki~A{|o<@a*AJN7D$1j zkB;b*YxZxbO0~(J_wBLYJht$Iug+#Y%}oE;k|8t|2M<<7N9a?AwYE4BXpOgySrC8C z$SY`=T^l)ak{#=VaS>dvoIOB>g#mqgYV}y;?O`CAID!oDR7&KjMSGN%eG68G^Qfd( z?Y2!@(lV97$7U4T@15y=1p%VD56+pe2U>Hwm;c&D7_jq+W%JN*Y|gCCDPrhX{i9ro zuXWc&SR^^b6_X$vyCui8ru-;tpSV4Z^7n~?x@LB29lMy)uE7IZLYeq@m=S&u`c~~6 z6gYT8DID(E459o=T*z~W0ORVc0P;bb%5KjyCY8b(j!#@qD!SefU5~T*Ksk64U?5>? ze8329ItJH-J;U{@c^PlUUoywG_k&p-@H)gSwWG!4a|n9?5;ZGpXxtwFwgZI)M7maM zbsqh|T^^)^3b6;5L=A1h!>##CUH1g=3JhUc z(i5FiE_9I@G(D=w6H11jeCw+VU}OR3KG^Ysf6r^AE5#hPsw_h?W|>$ zD!iUKiAALPlM@jZ*4dc2_ceOyeI~mKGS($DvYtvxg+K^`7SYS%XGSYNUMUBBNXH$} z&|PobJ`SbjGj7<>droz?pG{I_E$;c~W;;Ez;nE+8D$DAj2iIM#n=>4x)1uFvK1ZMg zdRcYdXBRA<&Grj=MsBi#)|_n4{qr(%E{@}1wWN9x)DmnxQ?+t(2UHrqwe`Emwyv@H zvZg_%n7A?!yR~N+ND6as!l*$jkX)&@Z^~p?T98%TmPZ{t!<~EMOdn-VliK|Z_WD)n zAGgn~U_y1_$2{s)`}R+TkIB7l$see}PvctBh=7bJNRtM8y%%Xma-Je3r7X84xVI^w z6J4x5cctX-RE!rM-OLoXKMdCdd((~!;v!aKl2WowG zT^)|C{af6?3OZm~!~T=T)dcyF8yM>2c!I$c_frMp-$ccKVxrmBq=ReX3j;mD8YfQ0 zeN8^A-tPR6ccilOQe5kcYG8toQ)7M-KE0qk4I%5Fk-}`KZ66{-m^X;pG3?WI$_4$b zj8v}&+sP0TaTURBMqGS~xogYfW5S9ogXv-8hYPX!mAksx^(T03$-wTj>v(28N>#y|CGlJvP~HeCs?+U!%wt(dqy+&wOzxVK>J^0UGkCIo%~KeLyk`uoTqKAk<9l2Bk;H!Go^mrA1h^$#hQtEfe<#ZKCDLo%n$+_ zGq}jR1B;tz`vMOQx(#;e{p02qZ@hLAI=x?5=}P$-w7Q(pj!X!CG+qTLcL1qV&3h`j zG5KvX1wTU}cCJDecw?TDO5#Curva%s%eDfBEW9Wbw;ann{Iy3?U+&|Ng+F zCGMb9vC5wKEFeeWmZi=3SXsw9r8d%9`qErY+`ID77MTv2gJfbqHAVcDSpg$H+%WfE zX?TgP^kz_U3&n4zXz?9iZABX0WLLa_8?&Zh^j6bN+2xp_0H8DUtFqYUW zyp>hhE?#|eM8)viK$LW{QG8r&bJmyyJf-C@7J$fc9=20h9)}pyW7?LTl8B2T--3WI zT=hYapA_|iG6y~yt@V2MR6k0dt`Afz8U(mY6>`qd|m=(QXC>o$IzJ${?UL!{A2tYdpLz^BGciEi%+$N@k z&V6%nPj?aibQK?T@q9l9TYBLKKlOXuA*^1?c^_)PpJCINuWn_N7F*{qtJJX~SGmcj z=iE`Ud!{No_tfb|a}%W1njOn0kAEWTv9A>0`lZk=7|gZ9S6p82mzL zUIl>%W6~XZb^`1X28DMqgVM@Wb&`S#93~vbsiIm1tyZRW!2 z^`Kg9dd!{-4j3#myFFWpfsCKi-$VM!PMSeiEYf)Rb49+mwfUIjry6XM#8YmcUo%3v z_p|!an~f=f>ss)i*j#u959>`yd>v718@VQUSp!#YDWA<8lVrRnvmc7IvL;j-JQW2m z+F)#@Xke}gn`FC;*gK#ObbKss0U3;iJ|K|=dGv0GeEU(TUTS1-%M67(6?Sbb%~h#S z*nZu7?&`m|>m@hTb_OQ~JEQ(jg}Gx>$uzP%`xFc*(h=7@&jGnx;yO=F_D)DV+0mR) z%TeIn*f;vFs7!NHD?4UD+m)e@)kFw*7jK+?i!MG)>ZNKDaW1`djZ^>U2)dn|P?kGc z5pckDm6d2}JsO2@&sw-Tp}W=Lo5rJzd}?wW2lIFxOh&8P{GGjwZXJDIw+chR%9r=D4%(%Awv; zOX`yp5RX%|pwj4=JkiXBln?O!w6$}gKiRwe()X_-rr3BF?_7lfe_h8iCm)0oAuTz$ zB*?`rPQ_fYusOJj2mQmhy-hpWTh59W+oie?(l+_mbMF&fj|stD!y7=xOvH#rR&1ZU zK7CEf>DU={m~Q-xjy|r9{r=Hs+&8pkIa64pSX&XG7FfTgSs}N_`9+D&N9|Rh7H)pp z30p>?1z)}@oa1(Pi8ingvNRn*zMIlpwK!dj7d$4{RAvE)N-n$oHY=Ltu%>EQe`*h* zDFnWx%^K>^%E=i2b!gpDWLvZi;ChWWkbkhx7hbhlB@6@aZvPlXGrACsN&FsILvC?2 z$6#0_pO0oOUP&Fcc`(4dtqT?>;;Zy5X}04VXG0L=^!>F!vgMBOdhYOm2fvjA;qv%x zNK&`_Z|hanal&KsJTTf*f`_NX=2mWiKIf8&Mq>&=>z?m7&|f9w@LAUZvA1Z09YtS_ z$Q~#v(>P%dYQ?`W_vNb&yO->0mZdr~Jf~sA2cT%2bmdj)(jD(UzpSc(_epZeJ*L9M zOC1sl2HL6K`iJKrPdNW}jx*M@1!;)4yP$L{bA{Smj%W=M^(DLViX8p|D++kuPY%=S z_P~`+3-64)B(|et6i?@9eN5|V)EmG{ZPmPGOg-_oM`U!xUoz%v<5RqI{HF|{82UCzBTL;O3xy9ykGGa(heIS&wU>Ju8h$8P;!?ZwVdf%ATI&-CJT-O929d|iD(z6{p1yb}%WQ)fkw^CiWv^9$G;jSgr-zy6|o&5bVi<9BD ziR8*1(A5xUJSO5erU4tXw+k#w&bgY+r`42KC+f*Uq_0FxJ4jLTUi3MD(K+^!eN)#> zc-UDL$TJOB$l9;|HAfhb`y&v6X}pb>moTfIN>iHuu2c+N)_gx~$u$Z%jAO|2l=i}L zHGnS5$LouO1UA(|PIHCUW{|A8ny51vj|vlPS;N3&0ys6l+C&`8y$xwS2Ef3!9~t^u zweZiV`2ymznf4n@w#pX!z??ZjpX<|~y{K+>ep$f}n>CpH89sI%go`vp(YYn%HE!+n z!k&_yP$DyoFXDCoVv}c(zq>!Wh&K&)<(EUcA1CpmZPZ)j-1qZ0VDhHY+-F(A)k8a8 zWVUOaX4h3(xY~$(KVH}I1{`;|QS6w~svF!jmha|cqCI3j(t?>;b42W8qSLnPTP0Oo zkOOv-$0`3Eium`VGvX92Q`cK-QJ&7`hwmlrcGqD1LFemRv$8MB zD9Yx$NM$g!N_>ZTH8#{J9{v%5OOH_`gCuoF_)*!UqZUEDN~T}F)% z*Y5=~+Lfa4u{^Gp+f0r*%2}7a;$W_SYl{E;E;l>dHyxuD<$|tZJJ-V1R;x{%8R!vC zkOV)D&N;7F`+WJT54vOX68v}XZ?-E3nf^=oM+dS=XQGFL{Y`3h?=G}I<*3F?45w9L zlI}}}e+@%=UoZn?SIYKrNIDwuwa`V@?FQC>)|EGL&3?S2*>0@jZ1$04VB#&Kvuxcf>d>~onLNc6I0|i)+Rv%`Jhw)qAwnx( zRk@S#(ok!3@D%Ozm#>b(W*D~vw%~u(i}dny-0~PvA}n)I+-3Q< zhecM4u5Q|6+Q!ay?K>&QG0bz=vW>f1tq>R7;a0P4*Q6@j$Q1+Ug~$`SR=Y5dPqbkE zONUcKC%%rn*7ZrG$|+rI3%{J+S0)*uUQ}0|LCf8O*gV;>&Zz9z?S^(|*EmmZpe=~o zO@4+|ZLw*9#jHBBWuj%=#aauXXZnvaM{Yune&YT-4%1{@y%_$2sRc7Rg!_UWIW-EtaA`ke7;@_{AQ zWDY5^xE;AduFwGvhL?ZcinD%G+kCIeY^C%7=)F|G$VBZ`g2G5uL&s;E=0yupZ5NS$ z8hr${<$QT-#GRb+py}Z=nyE%n#b6Gw{0#5v_CRRgU?aF~=e{r5{{7$R+@TBlQLb8i z))nI+umi23lMHu0rzJl!dC}#8%{X}>eWR#(X(Sx8P0WLSQ&w(wR@QJb1-)oUx&?pz z`uNkAkmZ~!P@&+D0d*_Ui2f1Ts0+a9BGo7Rv@3sPpfM`?>-fse+~FkFSN zWWU7F3N++g7z^Q}Oe1cP&uL$+U+N!#L(pel&eetmd>oA}cbaP3cP=pS>3lrX!Wy@c zvmg0yFGRQ}gDwg|&!CCg(O;H6Y^{6&*k?>$UrZKJ%~h|a2h$Fy>q2D;@oMJ15&dj0 zs*gz&BYj&$;)2`b<(-vN@2=60kEZBfJg-=_^F*TXte{N8K~8OYOtK?vxS5Sz;%kL^ z#uO~=uCSmRT?(oHmx%8AxxpK)E{v%-#ebd)^D#!^XX!*Tc>%EuD|4av=W3Er$e3m& zo^}g=?x^LOpRWcb5>nTTjA}6FSoXfNYSYEE!$^pUPT{5uVhGH27oJBx3yyA-UtO%? zE%GWQwKv^VK@0a&)|G9rEW%zbxz3}kJqfpgHYl+d{HQhr4_5B#VTRajba1~MuiM@d z;4ajJ5$h%A~*H z%sN!3x6RFP1%1E|LdPyQkXbi+{O`Q|_*+3qC9+-lQ|4Nb+u4g-Yf&3>(ML#fIeVp2 zQ7jGFL~riAxF79Vwmu?Yw7VX(DXSOH5 zA4}Ok(R;0DcWJ%LKy`sbS!@-Tii;OxM7r{#(qTpMM`chi*lSQRHyYt|`FPPIW&)pj z?i}S)lZ13hiH3xeOF>UTJ=G8?+!Ua-NjZ>ny7w`fW9Bb7QXF}4?gOq88oOuD-F9W! zx!Q0Wy5xK5%D?`)EFcZB*0hN2eT@!j1@``dezvBcL6)6%>wi1OTt#R7dxCM7{VL;w zoou+pyw{7@$O>Q}*qavfa}AOLI!&-#Oj!@{(I&l- z08{Af@FvHCm~sVLOS*!6^m$kYVyM%0CfZ4M>qmJy(Cn=-%KOav=Paoaam6IZkEi?R zk~uHOZV63Lg}~1Z$cJ~NFigS^%xQk`CfX5yHGIhj751Ua)?{iQU93*C{WR;RAG=7q z3Tk`>vXN%2y_`539?hE%wy{0Weu+|)rt2MK#~4L4>pFRCNih_tAH-ABN-K8+91&aP zs|UvOVBVuXMhuO(6tXYc4ye@%fq2sggPeuy*SIH1?|Hl*9xW5xpz~KNPh^aWu6?9! z2Di^5i%2+i-0;*wA=T>E(t`d11{-Tzi?oqM7l2si8*nwKDPw zh;Ahel-gthip|4X`zB-NU7G*MN~R{XN^3)6B^FEfbKY*jjuVsfS9Yb%iVb6R>;3h& zO|mRJl-!HI9V!mQBrGBcSE_0{X;ZG-{}1Z%w5qw-+z5RhH6j!qDv^3>68$du!{$ri zuNSj8;nK^Rd2FH2s#$ZpDcicol40O8DNzsFUwVr*27~SC^iIzf z;{~4X@4@Z~@|>_@foINfJJh!OQb1d_{XXWUQN{cJtO{O!G74K&NKK1ccp6cS)Fv;w z%A0&D2QTk$P*N7S^Ps(ShOkMtvCLm)eNv9iEpUiX9=G zoNe4e3Evc!8SLO!>kNZK?SgKS(K^-Hcnr`qI&KxNyCz2&{n)(ZspMP0VIBQ~3u0Ku z*}c((th}Rh&IJfxh}_JPIsKxe%14fLU1J}Hjy1dhol&)CzI#YiPAzOPGjWsQ?grca zP(US|t$%(Cxtgx0-7Bh|cm^8v2XoaXuhHH0AHzOhL_ell8Wlp#oZUWGA2VQAiv2*~ zdtu!wAIVMbBUiZhzx}MtxRp|Hekv-P88qiT3By42&@F4!*4K3C!Fq3b>}~Pxh2Uex zrs&!_(o2v%)m68ZefesD)m`GHA{d~ZOPeHOC`NzEU*h!*>(?vKq$msZg&Y%!wN0fE z`E_3JYBs}W4b(S^6mMS?rGFe;Th{Fm?3PNiAI?0iv$m9e$X#V^C3o6c!WCu9dr>jz z*(9+q+o(c*Jqs5{6JZCh@j3iL8Z?bPA_x_w?Y>iTzVcSJo-sc_ZsuV4&vi%goi}W` zl@(kFN3~vT{-WLfYnBXI>`7HH4OS4D*j=>)J!~JcI&0OV5 z`X+h$L%a#x=Zh1Ki)l=)s6ylJIwt7#U}C_!mIiRe^4JownM+gD<6A6!dVvd?`=J+w zlIxSF22lp7y$WgnRVM}POQG6aXQGb^mso!LhRGTA6fswd!#${yhB|iy+w~bS=A%uS zO2aYMgZ6CmyyG#XA@UaD$@4KQ9>4TlThHCz8peczhfx$$&=_?qb7ZB@Q4^8hvxaf! zEzbHD`W#q4PICXg&~-U^6Y}>$yZk9KWyggzpIRT{n_Hog*I~!8i&lJfOl#W<8f|VW z(|mR2P!>V)n%L*NH4Z(3+$0Wt5+UKyfo#Kl+XN2p#OxjWyX>ZzV6<3FMzlpd_SX)Os_HvD?a@Y4kZ>Q6e7Y96&;L;SI>+isb)Zm#y_+{|}yAd#_R zqPY3N!gBV72ow}W@hua*KmgFW`7CSftBa&Lmj+mgBy3Si`w~7ffm(NM7r5q4WNJT& zkBfjO{t%m7Jlhq&@TVQ8$_D3|o$d4&?R$Zp6#T^na26et&mYKQ#$#TzT zeOaChbX2;DFJE~XcvZ^(h{!gIZF7v%Z~3r$UpADrAuwe!ZDmuz1AM=n6+cU}ErxN9 zfBp`nUfX$0Cc}YUhT)F|taS4> z^kd@B36auEK#hoib_MRix9TX~TdYxC^2AB)t^$)q26RQw2U$MWzgdD0WkZzXH2o*f zEaoGM9WqPnlR#ulByI{s$+Jkbk^!A-75U|u#+dl*bZ#pvm?!xA(N+TM-3a$I+@s<3 z6?5T6nL%z2Z0d^efvMDGF!7eoQWD?or#$e0oS+J%{(3|B}# z%L*mce?wnjJ~feoMwzsfvx6Fy$&r1hGU1j;iCVCIfn#7?3zBY(iv~ZL@6B5=fSnjU z9E;IfJuQ0grgkb>n4M0fXhOQ|^l4-TFObHR*??)e`uEEVuY6ceIwCGi;;oE}~LAA$c{qvpR1aUn%`_$1pC*tkuZLazy zh$qnVNSg(VC@02NwXn&`^Jcqh>r+%WAfK1~J!5c~_5j{`{m1UE@H*Ja@tmFZ$Uggm zp=|+n_R~y`C%j@+F6a?&uh$FG%SG>tX!Zexk=GUPyMpl+`U4963Pj_tDmHZIms<3e zLJg6PuuGRB4VJw}i@%{F$8lGN-wQW&0SL1bg=Sqz)=KJ+l2>^nMfc!Eco|gGk-)2DtwI=e`q47-AOOw>5e~YAX3GeqWNKSe$ zVsRDp{y4EyLt=c@rtsq6V@57h_c$(8M9^Y^^q0OdyUuH5${woU{7;SRE=zd^Xm#}x z9mtq2gesY97gpn%Y;L7O)>{KoO<4k6-1T9F*)8k-sKjQ@`j;}d2jR#HF9(cn``|wP z*mI`h!x;T?WN~RWc0T3-WfJFhvY;w=I+}hAi5FMMsvD6+4`EN1b!tfNQwGIQHFZa( z`h_jUHIxT#u@VM4)t=}Y-u=eO*5si85QcPx+l?ZQqYaJ zQikex;j8+a^Qmy6KKz)ZqJi@&c`Yw4N1H9md+7Y-t8J;nv;PRpwo_~MV2lbh(gSXb z6LS!+Jp0rGBLg_pz&vTF&dgRzAY(*3kOlr|49t#V1jtDHb>f{`qHY`g+eEE{xArGQ z_J=wFbS0S4({j>X+Btr%oD{$7#ZtQN$W4?&4a~Qu43)CWSur+$z6S2maW5 zfS}#8b`1KalN+&{d*TyrzHX5dZ&+Q@jnh`{Sm1aHkBEa z#Tqv20B70yhC|VFM_ILzkK+D06!N#qVrBjMpJgXAEi0q2nE}JnqvYhn5iL9GSn?j^ z4s4(0YKWgW2Qz<6P@wiS(E@@Op$li^{`apFD=z9)nPd9aakdG#@9-)D54tJ?tkD^~ z#=n-c{otF^ueEmO8@=ZwyySLuR5lKe@^XxLH9U2x0?4902ScG^f8#PvpNswkky#nk zL31cEL zKo^}|HMmVt`6+zK4@8}tK8^bK5+jTRxwPZ5Y^JzmsaQ=cY|z&{ryA{hg6f!fSSJ-6 zv`Pt)HNO=;ygl;3W^Q(RPN(dk&q^`IwD*RU1)u3F?=|S1wezqoaV)5=t=; zVniI!B+=zN2K4Qsn5hoJ2KrmLU$ zZt<4wwy&dp+Aliaro6-WFefz|rYN^?KFVi*vt;~6->)_vNu+FqT{f?_Wp`<(qak=$ zBRtRf{bB6^b2p>ocwfHy59hFCOZqEB=;kaZXF*8@Lf1lb7;of@BqB(HAB+3#9G*6V zMB}ASJGbE$HtXxi+fKJn^jP3Ds+!EpNKm34V)SdW4g7YDzPV5Lo%)rf@z;FqUO{78 zxpOpVox)jr&G z-g~rU^U=z%fk&<%(oG4D@JuG|TjHmsyE=nvK!zUWou%)JTz^(Zjgzve%$uBEwONT8 zsA>io6MD=EC@4sF*>1C@?Q~)!(?P(#pic~4&HMyGDA6lJ(@!7@FH-mLs~AV~10FUO zHu(A^$xBL}rr!{Ba)(=BRdQn&|F8*5 zM?hszp!J{&Kt)SN`gjJBZ+wCpsdY;~z*Z!*tq(0C_Iob+pPt%17Z}QP2oznF z#U^2tC8A8&OZYlBdrFc5-aX$l+8BDtINL$YTfXF7R!tP{ zpPcKPRxHu05N&FAz~a(oAf*qf$nVT!=#Rl^HnU50^Smb}!StTb4;^@478!pB{ zp9zJmz^1V)JlLV7d#s$#5tuzDUj<=&W{Mu}=B;NsdvzUxt*=Mqfca62u@MrU}i?VM*wW~PK5qU*{t>~DDCvArUW2m*M=H+6AsA@m5kIP zH61@sw$?koxu)ruO3*(h?CJwwZIDnaaX`!Q2dLkJdN@24y~~Y?;S?-f-R@R0L$eQunnvLYo>6cusLZ5Zm!c! z+4)jF+-ql+63?^(}ayKI|zH@+E~B0hj4rUjHu?`6CymWR*M1)F;xw5o zKGTyLKH!T;hFi_fUk~To5ntn0u`H)}3xqS_^VN5BMwGvLH6g%DDe;1Ns8dB@=>l&T zZqbk2cc#jBc#2Pc7aUV+Ycm$!9{QowzmZ@MriEVAs#k%cZ%cOpC>=OGs`SrwTc(>J z7YE&fSo6G;__I0*LVI(yURS!_z58jV-tWIY11;yo2UkR1dX~Sv*NDDNKK3>bu*uT( zUVxNNWI0+tq83qaiC_yBBp;SJLG&nY0Y!}R$e@N0r)MIlu!y+%W_^N=MHEM#9?#F4 zJ*QJx^DI*j-U0nZe>5JKLM;q{&ycsYBFOb&F~VVl)3d9lGniO0jYO0WmP`_M@zHHD zEcX{6Lsp;i4!WIuOQvPal_PP=Uhg19bbBD9xQf zU9L+=D3ud{V8Bf3hrSdBGT9@5fY}wBAMY1mH z+5;4AC0;S!p$>gp7Rfr*NgFso9B>K^SJ}0OYRVas?D& z>8h#r_Xkcy24eZqIQ-+wIQQ3QZgfd>e#!?py~zh4z=mUD?Woi>w+nj_-f^xnDpTwf zFV#7ZY7n^sHzU$7XaWUsY!iQ_t;@hh%7CvYo3fQVH>t3sa!4^a8U+ALGjWN;9Qwf0y0PL~V zcLSme8({JTb^mPD36;GT^ca`j z?c09MZQ&-3k-w$)!blsQ+QJ_n^>yc}9*&%=Nz})1UxrpR@$57A;1AL05qBk9JgLoBgp?k-OF$ zcEfXdCc3|SJ+TM)Pcz?eWl3J=8%Yi z@XxoKL*-z{?KzgD#k}wI2RI`}dNtE!>7^WG&>W$i(5E zBz?}X7jJ&gGA&L-RvVkuw@em|p2=B=pTm+1uikXE6zLj?o!lNrs1nu&WeAqV&Ldb? zN}eZjHGsS8-Hb$VkG8fj(nK24Y#|D$NC)wTz^1s@!nU^{*c=d#k*7Y(Q z%ErH+Wv`d7DY9hVt19u*Z`?zSP%<>*Ndik5x$y^yXIhOux40qTl7EmgeiW9VgFzLR z?@&C2+n`&oPc@9ASd^?e&K)&{m~AjDE;?D_99{4J5V48uzgBS4Dq)%mX(PN1*`g-7 zC4&W~yO$>2&>h;^z%G7e=AkfS+crgBf(!W|j47^{3`R!3QP4Kmm6vP%3gRoje05Oj zL4I8yC~5%7A^MES9FCK^{n zO`Y_7k^3z2`v0s|)oK9XU~Lgb3cu1V__R#Q^lTMi)ck^3Qwin{7?!gv8IS_p?pw?b zfKw*42Ir0GkL3s7v`$P{$+4}EhPXy-3WXI(dL{hn7V~oA&)j4n7iR3Nk3>_%L5aM3 zKMzV^h1&noR-6ns)JKle9o45*+FyE8dn_v&ycQ2SanKHkaow7Gq8RHQ!5ick+=_YQ zi@ZkFT8Bb!bXIGt;>yPt)Wyvo#rJ*AUkD$&m82dFNjuYgkyE8~`&OTYTq$P64;n$~ z#T2KCQisXb?{7B{=Q@8xmmxEx<=Uh4HZZ@yJa>&A!rPvO3CP~#D#&_m={yyd(*|Y4 zClsrGL%C;T_EcC>nM93JK7ewBgnBu`O#YzOQ{C*=#r4B&2ojpJ#sUmCmNomqA_tDx z&w4`jS#jp@8k6*fUhPB^dG)-T^uaRs?n)TO+mA&<&dN`H6}jGv8`ng->Fw*fv8G^F zy9${_>dz9^Mz%HKR$W^#J~rZ@CC8Rp#XKWwCQiXRGF-iJ_3H?eI7?%zJ(TY?+q=xs zmM>q?NN@SCq8B#ooSCN5vKLN z9E!RFM2jO8O=~s#C*}HQQ`6<1x+FayUZ#Ik_Ke67hM5`r!c*76bDu$9uGi5z-9)eQ zsrss=*%9^>eK82!LubuS?lRab#?XP{PxBGEqdU31UFKm;- zK(g=$FS^p}9-CVMA1n+i9&%MpF&BnRK~%^=8N3TuC5fVuFJ>QFQf$;GXo#<|{>rqh z=m{$M5+rgrsFi(HPk~gpJ3lv^V7A29?Y~WX_TS& zTtYzYc9sUFXI!(!u9Oq<;Bh)vXoJvbuv3s}kD`;WBe;CXRv7v%cHBT0U|H zj$?6?Ar}L%YB^G6_TTCr*f~)U%U8-mFq`>tCbIkPfh0`j-U)%19vX`xl5aXsr zs~et9+OP#7F?D)FG|JZ&G3s$kw5!Knr5)bEkI5I4D@DFg6}m8)F;UeIbjJR<>J+Wh z>!=9bFJHduI`4wv-C)l3l+aG4zgA_~S^p3q>Xk?ShJPW{aHq`1Q45xBU!Q1(YKiA4 zCAVrH=3p~1Gmx!)&yE;}e$bC?AT2~}Je#^|M}2mjs>$t_;fp<^Pblk;?|#Bf%l1#; zz72t?n*W~SAbNPPdd)dP&+;b;(l)Pif3_9P9rENCKU6(TZ$x)G=V^`q7S{(kbmw+) zR>4L1AvmX3Qadp_TBRj{O)vPG!d7g8sel*QW?*uvxX!!4>X!b+igKpIYx-8lVQ$>u zx0y}Y-CbAeK<()E(vrBQvjwm(xGhL$xxxbzCyT*)x#mnb~XNsQ*Fia&9w1fI%t3L_+)lovFy zdb!@ohr$p8b=2WYU19anC-nVVLzKSu>XT=2viAY{6lfo>x^4DaGHsDHG;j0_>u?DP zBHs0XQJ48%qm23TRR-kLyIk4t;0CoN;x%t8^2EDW5+d2}jrMeF2V$3_KRz(GrqUY~PDwJnYYvoj0^tBm3-_XC{_Ci}}* zE|5$p#!((QTKmBm#v2rm3M#Z~a>92|{5A|CpK_igylwr%o-e#T_Nt>=v6Yl)$yJ}n z8CZ&@X9qtu;~)JSIIWw4^5w+o*VG~A?ftq_Jyp>}>oYLh`H1v5D`vs2MWzyW50*Un97VYg?RPp(`VG15LEnsPg?7qU09f4^ zr;Hjf!q^&##cfgFK3A1IpkwtP@vl~0)f$dHNtkY`JH*=Fsl5_+52=7mf^moBl0L}=wPDzE`q+H>w+TO*0vC0+7wf@`$^4SkF34)5wtY?S$WhZH27@<{KpPgR z?VKl6{QE}6i;@YFWrW!V63ctOIQ2?pU8epF;aYjjJIP;ZVAoBGdYC&bl41rmK$%nY zIT~oJ*LE}OiZp}By&~u6`{SHV!k}zB`KYJ)157VcY5rdkIw2?3)2<7MV!zTztdQTz z-!V7JsR!I_+})9W&|0c^*_qu#+}TF#3+YrYW?MehWMklXAMK)d18tpK@3zN$-j_bW*!!umn;YXzJLtR`B4X#rl-q#aG*3OzCHf}V&QQMc6xz|9 zrwHdITk!J$!~Torsy;l##k!i;7kMHVB@szTGf!8+ptLy}=tdf;=mjU6f}`tI-i)k9 zT8JIdO`oxVF^KFVm3Lg9mfG1DKq0^F5z;Nli@Y>!_>0b(stn%9N7wuK61lMId++lT zZrCgBJpYOXq?stPZac0-CocLH0OGJcQTvBG+359|3l7ZR7eZg?`6eUn*=0qp1FH4ATDK|EAV4zY8I(R{MpFti}d0fi7h=qCXHV(x{LbcQNk{ zDSLUGHmc9N0=n=iDKe+2)5gPD%d_(#m$>*oDUi|H>vvI>slg{IjsHwWsIvvuJu^VuJLVGx*gEIj~1zy zK~SCF|K+QHKh*6yQ2yov?`E*qE9BGuc4d~6)T2YlO~UEcymU1=UR@_UJDwYDJ$ns` zh9yMD+TAhyf~37+JcM6tt01!^o*j1fqiT}0%w=4|{H)OY4G)c#Q;P0^q2Ly$xG?D& zg`=#Ld5syEjMqdyNl*fm5TLSuo?82(GHdFYea` zGl~=o(C9TH6{}|=W2L8+7Ba&`%Lh1;tofmZZM&hCuzSX0suvMPJW0@9+Vfa;xFj;US19sFN9Bj_7=8)*s?9< z#gpmhuDgOypNcyv;8r4)gl5Cu33yHP#O_jSgR{abz1Plqd!MPx7L4HTp@tP5x}9R~ zDpx&I>_fn-Gp<5(FHTa;^!g$>5-Zu10Q4zj(((BGpd|aIk|q{N&nmCG{^9OjmivwH z-GZs3Bft6)Q+{iYCH@!UDm>+i!Y_F-au8^q1u{zM>9^KVakm#tUB7NMYTr9<3tGA2 z8H(l`=sJFc7_;?B!qls#Xd-*85j!R3-SfOVp83?dP(vUk?z@yM@Jv)894(8hWsK+D p;0jgQdt_sSw?`UQ*^H-$YUBO1=|)$durnt25)W=+z9xR@{eLeN+xGwf literal 0 HcmV?d00001 From b9244d63186ce8ba3e6d12f5df5128d9918f6339 Mon Sep 17 00:00:00 2001 From: Brandon Skrtich Date: Sun, 16 Mar 2014 11:57:48 -0600 Subject: [PATCH 002/146] Add PCLZIP alternative to ZipArchive Resolves #106 --- Classes/PHPWord/Settings.php | 56 +- Classes/PHPWord/Shared/File.php | 100 +- Classes/PHPWord/Shared/PCLZip/pclzip.lib.php | 5694 ++++++++++++++++++ Classes/PHPWord/Shared/ZipArchive.php | 204 + Classes/PHPWord/Writer/Exception.php | 49 + Classes/PHPWord/Writer/Word2007.php | 18 +- 6 files changed, 6110 insertions(+), 11 deletions(-) create mode 100644 Classes/PHPWord/Shared/PCLZip/pclzip.lib.php create mode 100644 Classes/PHPWord/Shared/ZipArchive.php create mode 100755 Classes/PHPWord/Writer/Exception.php diff --git a/Classes/PHPWord/Settings.php b/Classes/PHPWord/Settings.php index 0869f215..96fc7680 100644 --- a/Classes/PHPWord/Settings.php +++ b/Classes/PHPWord/Settings.php @@ -30,6 +30,12 @@ */ class PHPWord_Settings { + /** constants */ + + /** Available Zip library classes */ + const PCLZIP = 'PHPWord_Shared_ZipArchive'; + const ZIPARCHIVE = 'ZipArchive'; + /** * Compatibility option for XMLWriter * @@ -37,11 +43,20 @@ class PHPWord_Settings */ private static $_xmlWriterCompatibility = true; + /** + * Name of the class used for Zip file management + * e.g. + * ZipArchive + * + * @var string + */ + private static $_zipClass = self::ZIPARCHIVE; + /** * Set the compatibility option used by the XMLWriter * - * @param boolean $compatibility This sets the setIndent and setIndentString for better compatibility - * @return boolean Success or failure + * @param boolean $compatibility This sets the setIndent and setIndentString for better compatibility + * @return boolean Success or failure */ public static function setCompatibility($compatibility) { @@ -50,7 +65,7 @@ class PHPWord_Settings return true; } return false; - } + } // function setCompatibility() /** * Return the compatibility option used by the XMLWriter @@ -60,5 +75,36 @@ class PHPWord_Settings public static function getCompatibility() { return self::$_xmlWriterCompatibility; - } -} \ No newline at end of file + } // function getCompatibility() + + /** + * Set the Zip handler Class that PHPWord should use for Zip file management (PCLZip or ZipArchive) + * + * @param string $zipClass The Zip handler class that PHPWord should use for Zip file management + * e.g. PHPWord_Settings::PCLZip or PHPWord_Settings::ZipArchive + * @return boolean Success or failure + */ + public static function setZipClass($zipClass) + { + if (($zipClass === self::PCLZIP) || + ($zipClass === self::ZIPARCHIVE)) { + self::$_zipClass = $zipClass; + return TRUE; + } + return FALSE; + } // function setZipClass() + + /** + * Return the name of the Zip handler Class that PHPWord is configured to use (PCLZip or ZipArchive) + * or Zip file management + * + * @return string Name of the Zip handler Class that PHPWord is configured to use + * for Zip file management + * e.g. PHPWord_Settings::PCLZip or PHPWord_Settings::ZipArchive + */ + public static function getZipClass() + { + return self::$_zipClass; + } // function getZipClass() +} + diff --git a/Classes/PHPWord/Shared/File.php b/Classes/PHPWord/Shared/File.php index 26a206ba..03481f7f 100755 --- a/Classes/PHPWord/Shared/File.php +++ b/Classes/PHPWord/Shared/File.php @@ -30,11 +30,39 @@ */ class PHPWord_Shared_File { + /* + * Use Temp or File Upload Temp for temporary files + * + * @protected + * @var boolean + */ + protected static $_useUploadTempDirectory = FALSE; + + + /** + * Set the flag indicating whether the File Upload Temp directory should be used for temporary files + * + * @param boolean $useUploadTempDir Use File Upload Temporary directory (true or false) + */ + public static function setUseUploadTempDirectory($useUploadTempDir = FALSE) { + self::$_useUploadTempDirectory = (boolean) $useUploadTempDir; + } // function setUseUploadTempDirectory() + + + /** + * Get the flag indicating whether the File Upload Temp directory should be used for temporary files + * + * @return boolean Use File Upload Temporary directory (true or false) + */ + public static function getUseUploadTempDirectory() { + return self::$_useUploadTempDirectory; + } // function getUseUploadTempDirectory() + /** * Verify if a file exists * - * @param string $pFilename Filename - * @return bool + * @param string $pFilename Filename + * @return boolean */ public static function file_exists($pFilename) { @@ -45,7 +73,7 @@ class PHPWord_Shared_File /** * Returns canonicalized absolute pathname, also for ZIP archives * - * @param string $pFilename + * @param string $pFilename * @return string */ public static function realpath($pFilename) @@ -74,4 +102,70 @@ class PHPWord_Shared_File // Return return $returnValue; } + + /** + * Return the Image Type from a file + * + * @param string $filename + * @return return + */ + public static function imagetype($filename) { + if (function_exists('exif_imagetype')) { + return exif_imagetype($filename); + } else { + if ((list($width, $height, $type, $attr) = getimagesize( $filename )) !== false) { + return $type; + } + } + return false; + } + + /** + * Get the systems temporary directory. + * + * @return string + */ + public static function sys_get_temp_dir() + { + if (self::$_useUploadTempDirectory) { + // use upload-directory when defined to allow running on environments having very restricted + // open_basedir configs + if (ini_get('upload_tmp_dir') !== FALSE) { + if ($temp = ini_get('upload_tmp_dir')) { + if (file_exists($temp)) + return realpath($temp); + } + } + } + + // sys_get_temp_dir is only available since PHP 5.2.1 + // http://php.net/manual/en/function.sys-get-temp-dir.php#94119 + if ( !function_exists('sys_get_temp_dir')) { + if ($temp = getenv('TMP') ) { + if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); } + } + if ($temp = getenv('TEMP') ) { + if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); } + } + if ($temp = getenv('TMPDIR') ) { + if ((!empty($temp)) && (file_exists($temp))) { return realpath($temp); } + } + + // trick for creating a file in system's temporary dir + // without knowing the path of the system's temporary dir + $temp = tempnam(__FILE__, ''); + if (file_exists($temp)) { + unlink($temp); + return realpath(dirname($temp)); + } + + return null; + } + + // use ordinary built-in PHP function + // There should be no problem with the 5.2.4 Suhosin realpath() bug, because this line should only + // be called if we're running 5.2.1 or earlier + return realpath(sys_get_temp_dir()); + } + } diff --git a/Classes/PHPWord/Shared/PCLZip/pclzip.lib.php b/Classes/PHPWord/Shared/PCLZip/pclzip.lib.php new file mode 100644 index 00000000..4bf05a52 --- /dev/null +++ b/Classes/PHPWord/Shared/PCLZip/pclzip.lib.php @@ -0,0 +1,5694 @@ +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function create($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Invalid number / type of arguments"); + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + else { + } + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function add($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + function listContent() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function extract() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Trace + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, + $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + function extractByIndex($p_index) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + } + else { + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, + array (PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function delete() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + function properties() + { + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) + { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) + { + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) + { + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } + else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + function merge($p_archive_to_add) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) + { + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) + { + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorCode()); + } + else { + return($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorName($p_with_code=false) + { + $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' + ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' + ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->error_code.')'); + } + else { + return($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorInfo($p_full=false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorString()); + } + else { + if ($p_full) { + return($this->errorName(true)." : ".$this->error_string); + } + else { + return($this->error_string." [code ".$this->error_code."]"); + } + } + } + // -------------------------------------------------------------------------------- + + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + function privCheckFormat($p_level=0) + { + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) + { + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH : + case PCLZIP_OPT_REMOVE_PATH : + case PCLZIP_OPT_ADD_PATH : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i+1]; + if ((!is_integer($v_value)) || ($v_value<0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value*1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if ( is_string($p_options_list[$i+1]) + && ($p_options_list[$i+1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + } + else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + case PCLZIP_OPT_BY_PREG : + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT : + case PCLZIP_OPT_ADD_COMMENT : + case PCLZIP_OPT_PREPEND_COMMENT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, + "Missing parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, + "Wrong parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + + // ----- Remove spaces + $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i+1]); + } + else if (is_integer($p_options_list[$i+1])) { + $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_work_list = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag=false; + $v_sort_value=0; + for ($j=0; $j= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT : + case PCLZIP_CB_POST_EXTRACT : + case PCLZIP_CB_PRE_ADD : + case PCLZIP_CB_POST_ADD : + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '" + .$p_options_list[$i]."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privOptionDefaultThreshold(&$p_options) + { + $v_result=1; + + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } + + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + + if($last == 'g') + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit*1073741824; + if($last == 'm') + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit*1048576; + if($last == 'k') + $v_memory_limit = $v_memory_limit*1024; + + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + + + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) + { + $v_result=1; + + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + break; + + case PCLZIP_ATT_FILE_NEW_SHORT_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + case PCLZIP_ATT_FILE_NEW_FULL_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME : + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT : + $p_filedescr['content'] = $v_value; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '".$v_key."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result=1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) + && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; + } + else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } + else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } + else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + $v_result=1; + + // ----- Look if already open + if ($this->zip_fd != 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- +// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, + $p_options); + if ($v_result != 1) { + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=1; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } + else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; +// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; + $p_header['stored_filename'] = $p_filedescr['stored_filename']; + $p_header['extra'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for regular file + if ($p_filedescr['type']=='file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for regular folder + else if ($p_filedescr['type']=='folder') { + $p_header['external'] = 0x00000010; + $p_header['mtime'] = filemtime($p_filename); + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for virtual file + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = strlen($p_filedescr['content']); + } + + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = time(); + } + else { + $p_header['mtime'] = filemtime($p_filename); + } + + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } + else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Use "in memory" zip algo + else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + } + + // ----- Look for a virtual file (a file from string) + else if ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + } + + // ----- Look for a directory + else if ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) + { + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); + + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); + return PclZip::errorCode(); + } + + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); + + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) + { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCalculateStoredFilename(&$p_filedescr, &$p_options) + { + $v_result=1; + + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } + else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } + else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + else { + $p_remove_all_dir = 0; + } + + + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + } + + // ----- Look for path and/or short name change + else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'].'/'; + } + $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; + } + else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ( (substr($p_filename, 0, 2) == "./") + || (substr($p_remove_dir, 0, 2) == "./")) { + + if ( (substr($p_filename, 0, 2) == "./") + && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./".$p_remove_dir; + } + if ( (substr($p_filename, 0, 2) != "./") + && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, + $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } + else { + $v_stored_filename = substr($v_stored_filename, + strlen($p_remove_dir)); + } + } + } + + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); + + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + $v_result=1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, + $p_header['version_extracted'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], + $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, + $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], + $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], + $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, + $p_nb_entries, $p_size, + $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privConvertHeader2FileInfo($p_header, &$p_info) + { + $v_result=1; + + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if ( ($p_path == "") + || ( (substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") + && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) + { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") + { + $p_path = substr($p_path, 0, strlen($p_path)-1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) + { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for extraction in standard output + elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) + && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for normal extraction + else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, + $p_path, $p_remove_path, + $p_remove_all_path, + $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external']&0x00000010)==0x00000010) { + + $p_entry['status'] = "filtered"; + + return $v_result; + } + + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion + = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], + $p_entry['filename']); + if ($v_inclusion == 0) { + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, + "Filename '".$p_entry['filename']."' is " + ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + } + else { + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + return PclZip::errorCode(); + } + } + } + else { + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + + } + else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); + return PclZip::errorCode(); + } + + + // ----- Look for using temporary file to unzip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Look for extract in memory + else { + + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === FALSE) { + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + } + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); + + // ----- Close the temporary file + @fclose($v_dest_file); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + $p_entry['status'] = "write_error"; + return $v_result; + } + + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + @fclose($v_dest_file); + @gzclose($v_src_file); + + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } + else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === FALSE) { + // TBC + } + } + + // ----- Trace + } + else { + // TBC : error : can not extract a folder in a string + } + + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + + // ----- Get extra + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + + // ----- Get comment + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } + + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size-22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) + { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, + 'The central dir is not at the end of the archive.' + .' Some trailing bytes exists after the archive.'); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } + else + $p_central_dir['comment'] = ''; + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + + return $v_result; + } + + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + else { + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + unset($v_header_list[$v_nb_extracted]); + } + else + { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $izip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, + $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Remove every files : reset the file + else if ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + function privDirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) + { + // ----- Look for parent directory + if ($p_parent_dir != "") + { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) + { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privMerge(&$p_archive_to_add) + { + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Open the archive_to_add file + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorLog($p_error_code=0, $p_error_string='') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } + else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } + else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + $v_skip++; + } + else if ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/".$v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + } + // ----- Last '/' i.e. indicates a directory + else if ($i == (sizeof($v_list)-1)) { + $v_result = $v_list[$i]; + } + // ----- Double '/' inside the path + else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } + else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } + else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../'.$v_result; + $v_skip--; + } + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // -------------------------------------------------------------------------------- + function PclZipUtilPathInclusion($p_dir, $p_path) + { + $v_result = 1; + + // ----- Look for path beginning by ./ + if ( ($p_dir == '.') + || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + } + if ( ($p_path == '.') + || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + } + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilCopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + $v_result = 1; + + if ($p_mode==0) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilRename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // -------------------------------------------------------------------------------- + function PclZipUtilRename($p_src, $p_dest) + { + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } + else if (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilOptionText() + // Description : + // Translate option value in text. Mainly for debug purpose. + // Parameters : + // $p_option : the option value. + // Return Values : + // The option text value. + // -------------------------------------------------------------------------------- + function PclZipUtilOptionText($p_option) + { + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if (( ($v_prefix == 'PCLZIP_OPT') + || ($v_prefix == 'PCLZIP_CB_') + || ($v_prefix == 'PCLZIP_ATT')) + && ($v_list[$v_key] == $p_option)) { + return $v_key; + } + } + + $v_result = 'Unknown'; + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilTranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // -------------------------------------------------------------------------------- + function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // -------------------------------------------------------------------------------- + + +?> diff --git a/Classes/PHPWord/Shared/ZipArchive.php b/Classes/PHPWord/Shared/ZipArchive.php new file mode 100644 index 00000000..7a26f62b --- /dev/null +++ b/Classes/PHPWord/Shared/ZipArchive.php @@ -0,0 +1,204 @@ +_tempDir = PHPWord_Shared_File::sys_get_temp_dir(); + $this->_zip = new PclZip($fileName); + + return true; + } + + /** + * Close this zip archive + * + */ + public function close() { + } + + /** + * Add a new file to the zip archive. + * + * @param string $filename Directory/Name of the file to add to the zip archive + * @param string $localname Directory/Name of the file added to the zip + */ + public function addFile($filename, $localname = NULL) { + $filenameParts = pathinfo($filename); + $localnameParts = pathinfo($localname); + + // To Rename the file while adding it to the zip we + // need to create a temp file with the correct name + if ($filenameParts['basename'] != $localnameParts['basename']) { + $temppath = $this->_tempDir.'/'.$localnameParts['basename']; + copy($filename, $temppath); + $filename = $temppath; + $filenameParts = pathinfo($temppath); + } + + $res = $this->_zip->add($filename, + PCLZIP_OPT_REMOVE_PATH, $filenameParts['dirname'], + PCLZIP_OPT_ADD_PATH, $localnameParts["dirname"] + ); + + if ($res == 0) { + throw new PHPWord_Writer_Exception("Error zipping files : " . $this->_zip->errorInfo(true)); + return false; + } + + return true; + } + + /** + * Add a new file to the zip archive from a string of raw data. + * + * @param string $localname Directory/Name of the file to add to the zip archive + * @param string $contents String of data to add to the zip archive + */ + public function addFromString($localname, $contents) { + $filenameParts = pathinfo($localname); + + // Write $contents to a temp file + $handle = fopen($this->_tempDir.'/'.$filenameParts["basename"], "wb"); + fwrite($handle, $contents); + fclose($handle); + + // Add temp file to zip + $res = $this->_zip->add($this->_tempDir.'/'.$filenameParts["basename"], + PCLZIP_OPT_REMOVE_PATH, $this->_tempDir, + PCLZIP_OPT_ADD_PATH, $filenameParts["dirname"] + ); + if ($res == 0) { + throw new PHPWord_Writer_Exception("Error zipping files : " . $this->_zip->errorInfo(true)); + return false; + } + + // Remove temp file + unlink($this->_tempDir.'/'.$filenameParts["basename"]); + + return true; + } + + /** + * Find if given fileName exist in archive (Emulate ZipArchive locateName()) + * + * @param string $fileName Filename for the file in zip archive + * @return boolean + */ + public function locateName($fileName) { + $list = $this->_zip->listContent(); + $listCount = count($list); + $list_index = -1; + for ($i = 0; $i < $listCount; ++$i) { + if (strtolower($list[$i]["filename"]) == strtolower($fileName) || + strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + $list_index = $i; + break; + } + } + return ($list_index > -1); + } + + /** + * Extract file from archive by given fileName (Emulate ZipArchive getFromName()) + * + * @param string $fileName Filename for the file in zip archive + * @return string $contents File string contents + */ + public function getFromName($fileName) { + $list = $this->_zip->listContent(); + $listCount = count($list); + $list_index = -1; + for ($i = 0; $i < $listCount; ++$i) { + if (strtolower($list[$i]["filename"]) == strtolower($fileName) || + strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + $list_index = $i; + break; + } + } + + $extracted = ""; + if ($list_index != -1) { + $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); + } else { + $filename = substr($fileName, 1); + $list_index = -1; + for ($i = 0; $i < $listCount; ++$i) { + if (strtolower($list[$i]["filename"]) == strtolower($fileName) || + strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + $list_index = $i; + break; + } + } + $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); + } + if ((is_array($extracted)) && ($extracted != 0)) { + $contents = $extracted[0]["content"]; + } + + return $contents; + } + +} diff --git a/Classes/PHPWord/Writer/Exception.php b/Classes/PHPWord/Writer/Exception.php new file mode 100755 index 00000000..b4b6174e --- /dev/null +++ b/Classes/PHPWord/Writer/Exception.php @@ -0,0 +1,49 @@ +line = $line; + $e->file = $file; + throw $e; + } +} diff --git a/Classes/PHPWord/Writer/Word2007.php b/Classes/PHPWord/Writer/Word2007.php index e62341bf..bdd8e46a 100755 --- a/Classes/PHPWord/Writer/Word2007.php +++ b/Classes/PHPWord/Writer/Word2007.php @@ -77,11 +77,23 @@ class PHPWord_Writer_Word2007 implements PHPWord_Writer_IWriter } // Create new ZIP file and open it for writing - $objZip = new ZipArchive(); + $zipClass = PHPWord_Settings::getZipClass(); + $objZip = new $zipClass(); + + // Retrieve OVERWRITE and CREATE constants from the instantiated zip class + // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP + $ro = new ReflectionObject($objZip); + $zipOverWrite = $ro->getConstant('OVERWRITE'); + $zipCreate = $ro->getConstant('CREATE'); + + // Remove any existing file + if (file_exists($pFilename)) { + unlink($pFilename); + } // Try opening the ZIP file - if ($objZip->open($pFilename, ZIPARCHIVE::OVERWRITE) !== true) { - if ($objZip->open($pFilename, ZIPARCHIVE::CREATE) !== true) { + if ($objZip->open($pFilename, $zipOverWrite) !== true) { + if ($objZip->open($pFilename, $zipCreate) !== true) { throw new Exception("Could not open " . $pFilename . " for writing."); } } From 258c9c6b9e24c872947a91ce769af5fa478d69c3 Mon Sep 17 00:00:00 2001 From: ozilion Date: Thu, 20 Mar 2014 16:27:19 +0200 Subject: [PATCH 003/146] Added addCheckBox() function Created new file named CheckBox.php under Section folder. Added addCheckBox() function to Section.php and \Table\Cell.php files and _writeCheckbox(..) function to Base.php file. --- Classes/PHPWord/Section.php | 20 ++ Classes/PHPWord/Section/CheckBox.php | 198 +++++++++++++++++++ Classes/PHPWord/Section/Table/Cell.php | 20 ++ Classes/PHPWord/Writer/Word2007/Base.php | 114 +++++++++++ Classes/PHPWord/Writer/Word2007/Document.php | 12 +- 5 files changed, 359 insertions(+), 5 deletions(-) create mode 100644 Classes/PHPWord/Section/CheckBox.php diff --git a/Classes/PHPWord/Section.php b/Classes/PHPWord/Section.php index 07a17a31..f20cfd95 100755 --- a/Classes/PHPWord/Section.php +++ b/Classes/PHPWord/Section.php @@ -125,6 +125,26 @@ class PHPWord_Section return $text; } + /** + * Add a CheckBox Element + * + * @param string $text + * @param mixed $style + * @return PHPWord_Section_CheckBox + */ + public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) + { + if (!PHPWord_Shared_String::IsUTF8($name)) { + $name = utf8_encode($name); + } + if (!PHPWord_Shared_String::IsUTF8($text)) { + $text = utf8_encode($text); + } + $text = new PHPWord_Section_CheckBox($name, $text, $styleFont, $styleParagraph); + $this->_elementCollection[] = $text; + return $text; + } + /** * Add a Link Element * diff --git a/Classes/PHPWord/Section/CheckBox.php b/Classes/PHPWord/Section/CheckBox.php new file mode 100644 index 00000000..af02356a --- /dev/null +++ b/Classes/PHPWord/Section/CheckBox.php @@ -0,0 +1,198 @@ +setName($name); + $this->setText($text); + $paragraphStyle = $this->setParagraphStyle($paragraphStyle); + $this->setFontStyle($fontStyle, $paragraphStyle); + } + + /** + * Set Text style + * + * @param null|array|\PHPWord_Style_Font $style + * @param null|array|\PHPWord_Style_Paragraph $paragraphStyle + * @return PHPWord_Style_Font + */ + public function setFontStyle($style = null, $paragraphStyle = null) + { + if ($style instanceof PHPWord_Style_Font) { + $this->fontStyle = $style; + $this->setParagraphStyle($paragraphStyle); + } elseif (is_array($style)) { + $this->fontStyle = new PHPWord_Style_Font('text', $paragraphStyle); + $this->fontStyle->setArrayStyle($style); + } elseif (null === $style) { + $this->fontStyle = new PHPWord_Style_Font('text', $paragraphStyle); + } else { + $this->fontStyle = $style; + $this->setParagraphStyle($paragraphStyle); + } + return $this->fontStyle; + } + + /** + * Get Text style + * + * @return PHPWord_Style_Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + + /** + * Set Paragraph style + * + * @param null|array|\PHPWord_Style_Paragraph $style + * @return null|\PHPWord_Style_Paragraph + */ + public function setParagraphStyle($style = null) + { + if (is_array($style)) { + $this->paragraphStyle = new PHPWord_Style_Paragraph; + $this->paragraphStyle->setArrayStyle($style); + } elseif ($style instanceof PHPWord_Style_Paragraph) { + $this->paragraphStyle = $style; + } elseif (null === $style) { + $this->paragraphStyle = new PHPWord_Style_Paragraph; + } else { + $this->paragraphStyle = $style; + } + return $this->paragraphStyle; + } + + /** + * Get Paragraph style + * + * @return PHPWord_Style_Paragraph + */ + public function getParagraphStyle() + { + return $this->paragraphStyle; + } + + /** + * @param string $name + * @return $this + */ + public function setName($text) + { + $this->name = $text; + return $this; + } + + /** + * @param string $text + * @return $this + */ + public function setText($text) + { + $this->text = $text; + return $this; + } + + /** + * Get name content + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get Text content + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Get all Elements + * + * @return array + */ + public function getElements() + { + return $this->_elementCollection; + } + +} diff --git a/Classes/PHPWord/Section/Table/Cell.php b/Classes/PHPWord/Section/Table/Cell.php index f8d6d340..1a0d1c6a 100755 --- a/Classes/PHPWord/Section/Table/Cell.php +++ b/Classes/PHPWord/Section/Table/Cell.php @@ -113,6 +113,26 @@ class PHPWord_Section_Table_Cell return $text; } + /** + * Add a CheckBox Element + * + * @param string $text + * @param mixed $style + * @return PHPWord_Section_CheckBox + */ + public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) + { + if (!PHPWord_Shared_String::IsUTF8($name)) { + $name = utf8_encode($name); + } + if (!PHPWord_Shared_String::IsUTF8($text)) { + $text = utf8_encode($text); + } + $text = new PHPWord_Section_CheckBox($name, $text, $styleFont, $styleParagraph); + $this->_elementCollection[] = $text; + return $text; + } + /** * Add a Link Element * diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index e9249120..9ae5602b 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -289,6 +289,118 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart } } + /** + * Write CheckBox + */ + protected function _writeCheckbox(PHPWord_Shared_XMLWriter $objWriter = null, PHPWord_Section_CheckBox $Checkbox, $withoutP = false, $checkState = false) + { + $cbCount = 1; + $_elements = $Checkbox->getElements(); + if (count($_elements) > 1) { + $cbCount = $cbCount + 1; + } + + $styleFont = $Checkbox->getFontStyle(); + $SfIsObject = ($styleFont instanceof PHPWord_Style_Font) ? true : false; + + if (!$withoutP) { + $objWriter->startElement('w:p'); + + $styleParagraph = $Checkbox->getParagraphStyle(); + $SpIsObject = ($styleParagraph instanceof PHPWord_Style_Paragraph) ? true : false; + + if ($SpIsObject) { + $this->_writeParagraphStyle($objWriter, $styleParagraph); + } elseif (!$SpIsObject && !is_null($styleParagraph)) { + $objWriter->startElement('w:pPr'); + $objWriter->startElement('w:pStyle'); + $objWriter->writeAttribute('w:val', $styleParagraph); + $objWriter->endElement(); + $objWriter->endElement(); + } + } + + $strName = htmlspecialchars($Checkbox->getName()); + $strName = PHPWord_Shared_String::ControlCharacterPHP2OOXML($strName); + + $strText = htmlspecialchars($Checkbox->getText()); + $strText = PHPWord_Shared_String::ControlCharacterPHP2OOXML($strText); + + $objWriter->startElement('w:r'); + $objWriter->startElement('w:fldChar'); + $objWriter->writeAttribute('w:fldCharType', 'begin'); + $objWriter->startElement('w:ffData'); + $objWriter->startElement('w:name'); + $objWriter->writeAttribute('w:val', $strName); + $objWriter->endElement(); //w:name + + $objWriter->writeAttribute('w:enabled', ''); + $objWriter->startElement('w:calcOnExit'); + $objWriter->writeAttribute('w:val', '0'); + $objWriter->endElement(); //w:calcOnExit + + $objWriter->startElement('w:checkBox'); + $objWriter->writeAttribute('w:sizeAuto', ''); + $objWriter->startElement('w:default'); + if($checkState){ + $objWriter->writeAttribute('w:val', '1'); + }else{ + $objWriter->writeAttribute('w:val', '0'); + } + $objWriter->endElement(); //w:default + $objWriter->endElement(); //w:checkbox + $objWriter->endElement(); // w:ffData + $objWriter->endElement(); // w:fldChar + $objWriter->endElement(); // w:r + + $objWriter->startElement('w:bookmarkStart'); + $objWriter->writeAttribute('w:name', $strName); + $objWriter->writeAttribute('w:id', $cbCount); + $objWriter->startElement('w:r'); + $objWriter->startElement('w:instrText'); + $objWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $objWriter->writeRaw(' FORMCHECKBOX '); + $objWriter->endElement();// w:instrText + $objWriter->endElement(); // w:r + $objWriter->startElement('w:r'); + $objWriter->startElement('w:fldChar'); + $objWriter->writeAttribute('w:fldCharType', 'seperate'); + $objWriter->endElement();// w:fldChar + $objWriter->endElement(); // w:r + $objWriter->startElement('w:r'); + $objWriter->startElement('w:fldChar'); + $objWriter->writeAttribute('w:fldCharType', 'end'); + $objWriter->endElement();// w:fldChar + $objWriter->endElement(); // w:r + $objWriter->endElement(); // w:bookmarkStart + $objWriter->startElement('w:bookmarkEnd'); + $objWriter->writeAttribute('w:id', $cbCount); + $objWriter->endElement();// w:bookmarkEnd + + $objWriter->startElement('w:r'); + + if ($SfIsObject) { + $this->_writeTextStyle($objWriter, $styleFont); + } elseif (!$SfIsObject && !is_null($styleFont)) { + $objWriter->startElement('w:rPr'); + $objWriter->startElement('w:rStyle'); + $objWriter->writeAttribute('w:val', $styleFont); + $objWriter->endElement(); + $objWriter->endElement(); + } + + $objWriter->startElement('w:t'); + $objWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $objWriter->writeRaw($strText); + $objWriter->endElement(); + + $objWriter->endElement(); // w:r + + if (!$withoutP) { + $objWriter->endElement(); // w:p + } + } + /** * Write preserve text */ @@ -610,6 +722,8 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $this->_writeTextRun($objWriter, $element); } elseif ($element instanceof PHPWord_Section_Link) { $this->_writeLink($objWriter, $element); + } elseif ($element instanceof PHPWord_Section_CheckBox) { + $this->_writeCheckbox($objWriter, $element); } elseif ($element instanceof PHPWord_Section_TextBreak) { $this->_writeTextBreak($objWriter, $element); } elseif ($element instanceof PHPWord_Section_ListItem) { diff --git a/Classes/PHPWord/Writer/Word2007/Document.php b/Classes/PHPWord/Writer/Word2007/Document.php index abdd92cc..b6764b40 100755 --- a/Classes/PHPWord/Writer/Word2007/Document.php +++ b/Classes/PHPWord/Writer/Word2007/Document.php @@ -76,6 +76,8 @@ class PHPWord_Writer_Word2007_Document extends PHPWord_Writer_Word2007_Base $this->_writeTextRun($objWriter, $element); } elseif ($element instanceof PHPWord_Section_Link) { $this->_writeLink($objWriter, $element); + } elseif ($element instanceof PHPWord_Section_CheckBox) { + $this->_writeCheckbox($objWriter, $element); } elseif ($element instanceof PHPWord_Section_Title) { $this->_writeTitle($objWriter, $element); } elseif ($element instanceof PHPWord_Section_TextBreak) { @@ -259,11 +261,11 @@ class PHPWord_Writer_Word2007_Document extends PHPWord_Writer_Word2007_Base private function _writePageBreak(PHPWord_Shared_XMLWriter $objWriter = null) { $objWriter->startElement('w:p'); - $objWriter->startElement('w:r'); - $objWriter->startElement('w:br'); - $objWriter->writeAttribute('w:type', 'page'); - $objWriter->endElement(); - $objWriter->endElement(); + $objWriter->startElement('w:r'); + $objWriter->startElement('w:br'); + $objWriter->writeAttribute('w:type', 'page'); + $objWriter->endElement(); + $objWriter->endElement(); $objWriter->endElement(); } From 27840ab7103f4bd46190891c5d80b9f5a2393077 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Mon, 24 Mar 2014 13:43:20 -0400 Subject: [PATCH 004/146] Font-style addition: bgColor Signed-off-by: Julien Carignan --- Classes/PHPWord/Style/Font.php | 34 ++++++++++++++++++++++++ Classes/PHPWord/Writer/Word2007/Base.php | 10 +++++++ 2 files changed, 44 insertions(+) diff --git a/Classes/PHPWord/Style/Font.php b/Classes/PHPWord/Style/Font.php index 2aa6cbc6..66d82832 100755 --- a/Classes/PHPWord/Style/Font.php +++ b/Classes/PHPWord/Style/Font.php @@ -149,6 +149,18 @@ class PHPWord_Style_Font * @var string */ private $_fgColor = null; + + /** + * Background color + * + * @var string + */ + private $_bgColor = null; + /** + * Text line height + * + * @var int + */ /** * Text line height @@ -468,6 +480,28 @@ class PHPWord_Style_Font $this->_fgColor = $pValue; return $this; } + + /** + * Get background color + * + * @return string + */ + public function getBgColor() + { + return $this->_bgColor; + } + + /** + * Set background color + * + * @param string $pValue + * @return PHPWord_Style_Font + */ + public function setBgColor($pValue = null) + { + $this->_bgColor = $pValue; + return $this; + } /** * Get style type diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index d829bf92..0102979d 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -398,6 +398,7 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $color = $style->getColor(); $size = $style->getSize(); $fgColor = $style->getFgColor(); + $bgColor = $style->getBgColor(); $strikethrough = $style->getStrikethrough(); $underline = $style->getUnderline(); $superscript = $style->getSuperScript(); @@ -467,6 +468,15 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $objWriter->writeAttribute('w:val', $fgColor); $objWriter->endElement(); } + + // Background-Color + if (!is_null($bgColor)) { + $objWriter->startElement('w:shd'); + $objWriter->writeAttribute('w:val', "clear"); + $objWriter->writeAttribute('w:color', "auto"); + $objWriter->writeAttribute('w:fill', $bgColor); + $objWriter->endElement(); + } // Superscript/subscript if ($superscript || $subscript) { From e990c77b474aa39bdf6e883a9065d4794e6a2379 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Mon, 24 Mar 2014 13:50:37 -0400 Subject: [PATCH 005/146] Added height rules for table row - mostly for removing the added space after a table - Code mostly come from this discussion: https://phpword.codeplex.com/discussions/440933 - Usage: $table->addRow(5000, $rowStyle, "exact"); Signed-off-by: Julien Carignan --- Classes/PHPWord/Section/Table.php | 4 ++-- Classes/PHPWord/Section/Table/Row.php | 22 ++++++++++++++++++++-- Classes/PHPWord/Writer/Word2007/Base.php | 6 ++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Classes/PHPWord/Section/Table.php b/Classes/PHPWord/Section/Table.php index 80126cba..7efdf0b8 100755 --- a/Classes/PHPWord/Section/Table.php +++ b/Classes/PHPWord/Section/Table.php @@ -101,9 +101,9 @@ class PHPWord_Section_Table * @param int $height * @param mixed $style */ - public function addRow($height = null, $style = null) + public function addRow($height = null, $style = null, $hRules = null) { - $row = new PHPWord_Section_Table_Row($this->_insideOf, $this->_pCount, $height, $style); + $row = new PHPWord_Section_Table_Row($this->_insideOf, $this->_pCount, $height, $style, $hRules); $this->_rows[] = $row; return $row; } diff --git a/Classes/PHPWord/Section/Table/Row.php b/Classes/PHPWord/Section/Table/Row.php index dd8ea65c..5b239c89 100644 --- a/Classes/PHPWord/Section/Table/Row.php +++ b/Classes/PHPWord/Section/Table/Row.php @@ -37,7 +37,14 @@ class PHPWord_Section_Table_Row * @var int */ private $_height = null; - + + /** + * Row heightRules + * + * @var array + */ + private $_heightRules = array(); + /** * Row style * @@ -75,11 +82,12 @@ class PHPWord_Section_Table_Row * @param int $height * @param mixed $style */ - public function __construct($insideOf, $pCount, $height = null, $style = null) + public function __construct($insideOf, $pCount, $height = null, $style = null, $hRules = null) { $this->_insideOf = $insideOf; $this->_pCount = $pCount; $this->_height = $height; + $this->_heightRules = $hRules; $this->_style = new PHPWord_Style_Row(); if (!is_null($style)) { @@ -138,4 +146,14 @@ class PHPWord_Section_Table_Row { return $this->_height; } + + /** + * Get all row height rules + * + * @return array + */ + public function getHeightRules() + { + return $this->_heightRules; + } } diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index 0102979d..57bb7266 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -570,6 +570,7 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart for ($i = 0; $i < $_cRows; $i++) { $row = $_rows[$i]; $height = $row->getHeight(); + $heightRules = $row->getHeightRules(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $cantSplit = $rowStyle->getCantSplit(); @@ -580,6 +581,11 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $objWriter->startElement('w:trPr'); if (!is_null($height)) { $objWriter->startElement('w:trHeight'); + if(!is_null($heightRules)) { + $objWriter->startAttribute('w:hRule'); + $objWriter->text($heightRules); + $objWriter->endAttribute(); + } $objWriter->writeAttribute('w:val', $height); $objWriter->endElement(); } From e2cdf434ba315009b3eb5f32509477020d814209 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Mon, 24 Mar 2014 13:55:01 -0400 Subject: [PATCH 006/146] "php://output" content-length + tmpfile location - added content-length header to know the total file size during the download - Tmp file should go into sys_get_temp_dir() instead of "./" Signed-off-by: Julien Carignan --- Classes/PHPWord/Writer/Word2007.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/PHPWord/Writer/Word2007.php b/Classes/PHPWord/Writer/Word2007.php index 16d66c66..2589e9ef 100755 --- a/Classes/PHPWord/Writer/Word2007.php +++ b/Classes/PHPWord/Writer/Word2007.php @@ -113,7 +113,7 @@ class PHPWord_Writer_Word2007 implements PHPWord_Writer_IWriter // If $pFilename is php://output or php://stdout, make it a temporary file... $originalFilename = $pFilename; if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { - $pFilename = @tempnam('./', 'phppttmp'); + $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_');// temp files should go to system temp directory (if a user cancels a download, the file stays) if ($pFilename == '') { $pFilename = $originalFilename; } @@ -236,6 +236,7 @@ class PHPWord_Writer_Word2007 implements PHPWord_Writer_IWriter // If a temporary file was used, copy it to the correct file stream if ($originalFilename != $pFilename) { + header('Content-Length: '.filesize($pFilename));// if php://output, we want to know the total file size when downloading if (copy($pFilename, $originalFilename) === false) { throw new Exception("Could not copy temporary zip file $pFilename to $originalFilename."); } From 6796883d43f5cecd43844204926ab048bb4be6ef Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Mon, 24 Mar 2014 14:03:02 -0400 Subject: [PATCH 007/146] added samples for bgColor and tableRowHeightRules Signed-off-by: Julien Carignan --- samples/Sample_20_BGColor.php | 30 ++++++++++++++++++++ samples/Sample_21_TableRowRules.php | 44 +++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 samples/Sample_20_BGColor.php create mode 100644 samples/Sample_21_TableRowRules.php diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php new file mode 100644 index 00000000..1122ba3d --- /dev/null +++ b/samples/Sample_20_BGColor.php @@ -0,0 +1,30 @@ +'); +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); +$section = $PHPWord->createSection(); + +$section->addText("This is some text highlighted using fgColor (limited to 15 colors) ", array("fgColor" => PHPWord_Style_Font::FGCOLOR_YELLOW)); +$section->addText("This one uses bgColor and is using hex value (0xfbbb10)", array("bgColor" => "fbbb10")); +$section->addText("Compatible with font colors", array("color"=>"0000ff", "bgColor" => "fbbb10")); + + +// Save file +$name = basename(__FILE__, '.php'); +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); +foreach ($writers as $writer => $extension) { + echo date('H:i:s'), " Write to {$writer} format", EOL; + $objWriter = PHPWord_IOFactory::createWriter($PHPWord, $writer); + $objWriter->save("{$name}.{$extension}"); + rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +} + + +// Done +echo date('H:i:s'), " Done writing file(s)", EOL; +echo date('H:i:s'), " Peak memory usage: ", (memory_get_peak_usage(true) / 1024 / 1024), " MB", EOL; diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php new file mode 100644 index 00000000..83d03e0c --- /dev/null +++ b/samples/Sample_21_TableRowRules.php @@ -0,0 +1,44 @@ +'); +require_once '../Classes/PHPWord.php'; + +// New Word Document +echo date('H:i:s') , ' Create new PHPWord object' , EOL; +$PHPWord = new PHPWord(); +$section = $PHPWord->createSection(); + +$section->addText("By default, a table row adds a textbreak after its content (notice the red border), even if the row height is <= height of the content"); + +$table1 = $section->addTable(array("cellMargin"=> 0, "cellMarginRight"=> 0, "cellMarginBottom"=> 0, "cellMarginLeft"=> 0)); +$table1->addRow(3750); +$cell1 = $table1->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "ff0000")); +$cell1->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); + +$section->addTextBreak(); +$section->addText("But if we set the row rule \"exact\", we get rid of the textbreak!"); + +$table2 = $section->addTable(array("cellMargin"=> 0, "cellMarginRight"=> 0, "cellMarginBottom"=> 0, "cellMarginLeft"=> 0)); +$table2->addRow(3750, null, "exact"); +$cell2 = $table2->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "00ff00")); +$cell2->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); + +$section->addTextBreak(); +$section->addText("In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips."); +$section->addText("So: $"."table2->addRow(3750, null, 'exact');"); + +// Save file +$name = basename(__FILE__, '.php'); +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); +foreach ($writers as $writer => $extension) { + echo date('H:i:s'), " Write to {$writer} format", EOL; + $objWriter = PHPWord_IOFactory::createWriter($PHPWord, $writer); + $objWriter->save("{$name}.{$extension}"); + rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +} + + +// Done +echo date('H:i:s'), " Done writing file(s)", EOL; +echo date('H:i:s'), " Peak memory usage: ", (memory_get_peak_usage(true) / 1024 / 1024), " MB", EOL; From a6568e988b0de61cb7d20369ef604a42758a2613 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 26 Mar 2014 17:21:23 +0700 Subject: [PATCH 008/146] Proposed simplified docblock --- src/PhpWord/PhpWord.php | 22 +++------------- tests/PhpWord/Tests/PhpWordTest.php | 39 ++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index eb8c45ec..1fa0c4b8 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -2,25 +2,11 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord + * PHP version 5.3 * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL + * @version 0.9.0 */ namespace PhpOffice\PhpWord; diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index bcabcfb3..f7133358 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -1,4 +1,14 @@ loadTemplate($templateFqfn); From ab6503eb0dcd7305c5e9895f095672440b2d39ef Mon Sep 17 00:00:00 2001 From: ozilion Date: Thu, 27 Mar 2014 10:17:07 +0200 Subject: [PATCH 009/146] Test folder updated Test folder updated for new file CheckBoxText --- Classes/PHPWord/Section.php | 1 + Classes/PHPWord/Section/CheckBox.php | 5 +-- Classes/PHPWord/Section/Table/Cell.php | 1 + Classes/PHPWord/Section/Text.php | 2 +- Tests/PHPWord/AutoloaderTest.php | 1 + Tests/PHPWord/Section/CheckBoxTest.php | 42 ++++++++++++++++++++++ Tests/PHPWord/Section/Table/CellTest.php | 9 +++++ Tests/PHPWord/SectionTest.php | 2 ++ Tests/PHPWord/Writer/Word2007/BaseTest.php | 20 +++++++++++ 9 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 Tests/PHPWord/Section/CheckBoxTest.php diff --git a/Classes/PHPWord/Section.php b/Classes/PHPWord/Section.php index f20cfd95..e65267df 100755 --- a/Classes/PHPWord/Section.php +++ b/Classes/PHPWord/Section.php @@ -128,6 +128,7 @@ class PHPWord_Section /** * Add a CheckBox Element * + * @param string $name * @param string $text * @param mixed $style * @return PHPWord_Section_CheckBox diff --git a/Classes/PHPWord/Section/CheckBox.php b/Classes/PHPWord/Section/CheckBox.php index af02356a..03f8228a 100644 --- a/Classes/PHPWord/Section/CheckBox.php +++ b/Classes/PHPWord/Section/CheckBox.php @@ -68,6 +68,7 @@ class PHPWord_Section_CheckBox /** * Create a new Text Element * + * @param string $name * @param string $text * @param null|array|\PHPWord_Style_Font $fontStyle * @param null|array|\PHPWord_Style_Paragraph $paragraphStyle @@ -149,9 +150,9 @@ class PHPWord_Section_CheckBox * @param string $name * @return $this */ - public function setName($text) + public function setName($name) { - $this->name = $text; + $this->name = $name; return $this; } diff --git a/Classes/PHPWord/Section/Table/Cell.php b/Classes/PHPWord/Section/Table/Cell.php index 1a0d1c6a..e18dd829 100755 --- a/Classes/PHPWord/Section/Table/Cell.php +++ b/Classes/PHPWord/Section/Table/Cell.php @@ -116,6 +116,7 @@ class PHPWord_Section_Table_Cell /** * Add a CheckBox Element * + * @param string $name * @param string $text * @param mixed $style * @return PHPWord_Section_CheckBox diff --git a/Classes/PHPWord/Section/Text.php b/Classes/PHPWord/Section/Text.php index 8631b66e..2a96a2d9 100755 --- a/Classes/PHPWord/Section/Text.php +++ b/Classes/PHPWord/Section/Text.php @@ -139,7 +139,7 @@ class PHPWord_Section_Text $this->text = $text; return $this; } - + /** * Get Text content * diff --git a/Tests/PHPWord/AutoloaderTest.php b/Tests/PHPWord/AutoloaderTest.php index 03e16db0..b1899770 100644 --- a/Tests/PHPWord/AutoloaderTest.php +++ b/Tests/PHPWord/AutoloaderTest.php @@ -1,6 +1,7 @@ assertInstanceOf('PHPWord_Section_CheckBox', $oCheckBox); + $this->assertEquals(null, $oCheckBox->getText()); + $this->assertInstanceOf('PHPWord_Style_Font', $oCheckBox->getFontStyle()); + $this->assertInstanceOf('PHPWord_Style_Paragraph', $oCheckBox->getParagraphStyle()); + } + + public function testCheckBox() + { + $oCheckBox = new PHPWord_Section_CheckBox('CheckBox'); + + $this->assertEquals($oCheckBox->getText(), 'CheckBox'); + } + + public function testFont() + { + $oCheckBox = new PHPWord_Section_CheckBox('CheckBox', 'fontStyle'); + $this->assertEquals($oCheckBox->getFontStyle(), 'fontStyle'); + + $oCheckBox->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); + $this->assertInstanceOf('PHPWord_Style_Font', $oCheckBox->getFontStyle()); + } + + public function testParagraph() + { + $oCheckBox = new PHPWord_Section_CheckBox('CheckBox', 'fontStyle', 'paragraphStyle'); + $this->assertEquals($oCheckBox->getParagraphStyle(), 'paragraphStyle'); + + $oCheckBox->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); + $this->assertInstanceOf('PHPWord_Style_Paragraph', $oCheckBox->getParagraphStyle()); + } +} diff --git a/Tests/PHPWord/Section/Table/CellTest.php b/Tests/PHPWord/Section/Table/CellTest.php index 30a7fcdb..be2878f1 100644 --- a/Tests/PHPWord/Section/Table/CellTest.php +++ b/Tests/PHPWord/Section/Table/CellTest.php @@ -40,6 +40,15 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PHPWord_Section_Text', $element); } + public function testaddCheckBox() + { + $oCell = new PHPWord_Section_Table_Cell('section', 1); + $element = $oCell->addCheckBox('check1', 'text'); + + $this->assertCount(1, $oCell->getElements()); + $this->assertInstanceOf('PHPWord_Section_CheckBox', $element); + } + public function testAddTextNotUTF8() { $oCell = new PHPWord_Section_Table_Cell('section', 1); diff --git a/Tests/PHPWord/SectionTest.php b/Tests/PHPWord/SectionTest.php index ac540d06..1bcd108c 100644 --- a/Tests/PHPWord/SectionTest.php +++ b/Tests/PHPWord/SectionTest.php @@ -61,6 +61,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase /** * @covers PHPWord_Section::addText + * @covers PHPWord_Section::addCheckBox * @covers PHPWord_Section::addLink * @covers PHPWord_Section::addTextBreak * @covers PHPWord_Section::addPageBreak @@ -88,6 +89,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section = new PHPWord_Section(0); $section->addText(utf8_decode('ä')); + $section->addCheckBox('check1', utf8_decode('ä')); $section->addLink(utf8_decode('http://äää.com'), utf8_decode('ä')); $section->addTextBreak(); $section->addPageBreak(); diff --git a/Tests/PHPWord/Writer/Word2007/BaseTest.php b/Tests/PHPWord/Writer/Word2007/BaseTest.php index fde6e30b..1ede88f4 100644 --- a/Tests/PHPWord/Writer/Word2007/BaseTest.php +++ b/Tests/PHPWord/Writer/Word2007/BaseTest.php @@ -43,6 +43,26 @@ class BaseTest extends \PHPUnit_Framework_TestCase $this->assertEquals($pStyle, $doc->getElementAttribute($element, 'w:val')); } + /** + * covers ::_writeCheckbox + */ + public function testWriteCheckbox() + { + $rStyle = 'rStyle'; + $pStyle = 'pStyle'; + + $PHPWord = new PHPWord(); + $PHPWord->addFontStyle($rStyle, array('bold' => true)); + $PHPWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); + $section = $PHPWord->createSection(); + $section->addCheckbox('Check1', 'Test', $rStyle, $pStyle); + $doc = TestHelperDOCX::getDocument($PHPWord); + + $element = $doc->getElement('/w:document/w:body/w:p/w:checkbox/w:r/w:t'); + + $this->assertEquals($expected, $element->nodeValue); + } + /** * covers ::_writeTextRun */ From b3c5a76a64bc2f130d2c95c329b230354f21b3cc Mon Sep 17 00:00:00 2001 From: gianis6 Date: Thu, 27 Mar 2014 16:33:02 +0100 Subject: [PATCH 010/146] Update Base.php added tblGrid element so that LibreOffice and OpenOffice can size the tables columns properly --- src/PhpWord/Writer/Word2007/Base.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index d76d543d..0f93f488 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -571,6 +571,30 @@ class Base extends WriterPart if ($_cRows > 0) { $xmlWriter->startElement('w:tbl'); + + $cellWidths = array(); + for($i=0; $i<$_cRows; $i++) + { + $row = $_rows[$i]; + $cells = $row->getCells(); + if(count($cells) <= count($cellWidths)) + continue; + + $cellWidths = array(); + foreach ($cells as $cell) + $cellWidths[] = $cell->getWidth(); + } + + $xmlWriter->startElement('w:tblGrid'); + foreach($cellWidths as $width) + { + $xmlWriter->startElement('w:gridCol'); + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + $tblStyle = $table->getStyle(); $tblWidth = $table->getWidth(); if ($tblStyle instanceof PhpOffice\PhpWord\Style\Table) { From e6a26dd8fc5b0f53c73e347d519683238e392987 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 27 Mar 2014 23:55:06 +0700 Subject: [PATCH 011/146] Simplify all classes docblock --- src/PhpWord/Autoloader.php | 22 +++---------------- src/PhpWord/DocumentProperties.php | 22 +++---------------- src/PhpWord/Exceptions/Exception.php | 22 +++---------------- .../Exceptions/InvalidImageException.php | 22 +++---------------- .../Exceptions/InvalidObjectException.php | 22 +++---------------- .../Exceptions/InvalidStyleException.php | 22 +++---------------- .../UnsupportedImageTypeException.php | 22 +++---------------- src/PhpWord/Footnote.php | 22 +++---------------- src/PhpWord/HashTable.php | 22 +++---------------- src/PhpWord/IOFactory.php | 22 +++---------------- src/PhpWord/Media.php | 22 +++---------------- src/PhpWord/PhpWord.php | 4 +--- src/PhpWord/Reader/AbstractReader.php | 22 +++---------------- src/PhpWord/Reader/IReader.php | 22 +++---------------- src/PhpWord/Reader/Word2007.php | 22 +++---------------- src/PhpWord/Section.php | 22 +++---------------- src/PhpWord/Section/Footer.php | 22 +++---------------- src/PhpWord/Section/Footer/PreserveText.php | 22 +++---------------- src/PhpWord/Section/Footnote.php | 22 +++---------------- src/PhpWord/Section/Header.php | 22 +++---------------- src/PhpWord/Section/Image.php | 22 +++---------------- src/PhpWord/Section/Link.php | 22 +++---------------- src/PhpWord/Section/ListItem.php | 22 +++---------------- src/PhpWord/Section/Object.php | 22 +++---------------- src/PhpWord/Section/PageBreak.php | 22 +++---------------- src/PhpWord/Section/Settings.php | 22 +++---------------- src/PhpWord/Section/Table.php | 22 +++---------------- src/PhpWord/Section/Table/Cell.php | 22 +++---------------- src/PhpWord/Section/Table/Row.php | 22 +++---------------- src/PhpWord/Section/Text.php | 22 +++---------------- src/PhpWord/Section/TextBreak.php | 22 +++---------------- src/PhpWord/Section/TextRun.php | 22 +++---------------- src/PhpWord/Section/Title.php | 22 +++---------------- src/PhpWord/Settings.php | 22 +++---------------- src/PhpWord/Shared/Drawing.php | 22 +++---------------- src/PhpWord/Shared/Font.php | 22 +++---------------- src/PhpWord/Shared/String.php | 22 +++---------------- src/PhpWord/Shared/XMLWriter.php | 22 +++---------------- src/PhpWord/Shared/ZipStreamWrapper.php | 22 +++---------------- src/PhpWord/Style.php | 22 +++---------------- src/PhpWord/Style/Cell.php | 22 +++---------------- src/PhpWord/Style/Font.php | 22 +++---------------- src/PhpWord/Style/Image.php | 22 +++---------------- src/PhpWord/Style/ListItem.php | 22 +++---------------- src/PhpWord/Style/Paragraph.php | 22 +++---------------- src/PhpWord/Style/Row.php | 22 +++---------------- src/PhpWord/Style/TOC.php | 22 +++---------------- src/PhpWord/Style/Tab.php | 22 +++---------------- src/PhpWord/Style/Table.php | 22 +++---------------- src/PhpWord/Style/Tabs.php | 22 +++---------------- src/PhpWord/TOC.php | 22 +++---------------- src/PhpWord/Template.php | 22 +++---------------- src/PhpWord/Writer/IWriter.php | 22 +++---------------- src/PhpWord/Writer/ODText.php | 22 +++---------------- src/PhpWord/Writer/ODText/Content.php | 22 +++---------------- src/PhpWord/Writer/ODText/Manifest.php | 22 +++---------------- src/PhpWord/Writer/ODText/Meta.php | 22 +++---------------- src/PhpWord/Writer/ODText/Mimetype.php | 22 +++---------------- src/PhpWord/Writer/ODText/Styles.php | 22 +++---------------- src/PhpWord/Writer/ODText/WriterPart.php | 22 +++---------------- src/PhpWord/Writer/RTF.php | 22 +++---------------- src/PhpWord/Writer/Word2007.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Base.php | 22 +++---------------- src/PhpWord/Writer/Word2007/ContentTypes.php | 22 +++---------------- src/PhpWord/Writer/Word2007/DocProps.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Document.php | 22 +++---------------- src/PhpWord/Writer/Word2007/DocumentRels.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Footer.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Footnotes.php | 22 +++---------------- src/PhpWord/Writer/Word2007/FootnotesRels.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Header.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Rels.php | 22 +++---------------- src/PhpWord/Writer/Word2007/Styles.php | 22 +++---------------- src/PhpWord/Writer/Word2007/WriterPart.php | 22 +++---------------- tests/PhpWord/Tests/AutoloaderTest.php | 14 ++++++++++++ .../PhpWord/Tests/DocumentPropertiesTest.php | 12 +++++++++- .../Tests/Exceptions/ExceptionTest.php | 14 ++++++++++++ .../Exceptions/InvalidImageExceptionTest.php | 14 ++++++++++++ .../Exceptions/InvalidStyleExceptionTest.php | 14 ++++++++++++ .../UnsupportedImageTypeExceptionTest.php | 14 ++++++++++++ tests/PhpWord/Tests/IOFactoryTest.php | 12 +++++++++- tests/PhpWord/Tests/MediaTest.php | 14 ++++++++++++ tests/PhpWord/Tests/PhpWordTest.php | 6 ++--- tests/PhpWord/Tests/Reader/Word2007Test.php | 14 ++++++++++++ .../Tests/Section/Footer/PreserveTextTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/FooterTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/FootnoteTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/HeaderTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/ImageTest.php | 11 ++++++++++ tests/PhpWord/Tests/Section/LinkTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/ListItemTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/ObjectTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/PageBreakTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/SettingsTest.php | 14 ++++++++++++ .../PhpWord/Tests/Section/Table/CellTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/Table/RowTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/TableTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/TextBreakTest.php | 12 +++++++++- tests/PhpWord/Tests/Section/TextRunTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/TextTest.php | 14 ++++++++++++ tests/PhpWord/Tests/Section/TitleTest.php | 14 ++++++++++++ tests/PhpWord/Tests/SectionTest.php | 12 +++++++++- tests/PhpWord/Tests/SettingsTest.php | 12 +++++++++- tests/PhpWord/Tests/Shared/DrawingTest.php | 11 ++++++++++ tests/PhpWord/Tests/Shared/FontTest.php | 11 ++++++++++ tests/PhpWord/Tests/Shared/StringTest.php | 12 +++++++++- tests/PhpWord/Tests/Style/CellTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/FontTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/ImageTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/ListItemTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/ParagraphTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/RowTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/TOCTest.php | 12 +++++++++- tests/PhpWord/Tests/Style/TableTest.php | 11 ++++++++++ tests/PhpWord/Tests/Style/TabsTest.php | 11 ++++++++++ tests/PhpWord/Tests/StyleTest.php | 12 +++++++++- tests/PhpWord/Tests/TOCTest.php | 12 +++++++++- tests/PhpWord/Tests/TemplateTest.php | 12 +++++++++- .../Tests/Writer/ODText/ContentTest.php | 11 +++++++++- .../Tests/Writer/ODText/WriterPartTest.php | 12 +++++++--- tests/PhpWord/Tests/Writer/ODTextTest.php | 11 +++++++++- tests/PhpWord/Tests/Writer/RTFTest.php | 11 +++++++++- .../Tests/Writer/Word2007/BaseTest.php | 11 +++++++++- .../Tests/Writer/Word2007/DocumentTest.php | 10 +++++++++ .../Tests/Writer/Word2007/FooterTest.php | 12 +++++++--- .../Tests/Writer/Word2007/FootnotesTest.php | 10 +++++++++ .../Tests/Writer/Word2007/HeaderTest.php | 12 +++++++--- .../Tests/Writer/Word2007/StylesTest.php | 10 +++++++++ .../Tests/Writer/Word2007/WriterPartTest.php | 12 +++++++--- tests/PhpWord/Tests/Writer/Word2007Test.php | 11 +++++++++- 130 files changed, 877 insertions(+), 1421 deletions(-) diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index d1d96a75..5bb331ab 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 8ea683ea..188a417d 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Exceptions/Exception.php b/src/PhpWord/Exceptions/Exception.php index 30f1d8f1..44323baa 100755 --- a/src/PhpWord/Exceptions/Exception.php +++ b/src/PhpWord/Exceptions/Exception.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Exceptions; diff --git a/src/PhpWord/Exceptions/InvalidImageException.php b/src/PhpWord/Exceptions/InvalidImageException.php index 380cb382..319a6203 100644 --- a/src/PhpWord/Exceptions/InvalidImageException.php +++ b/src/PhpWord/Exceptions/InvalidImageException.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Exceptions; diff --git a/src/PhpWord/Exceptions/InvalidObjectException.php b/src/PhpWord/Exceptions/InvalidObjectException.php index 5a7c3536..c6a89ac7 100644 --- a/src/PhpWord/Exceptions/InvalidObjectException.php +++ b/src/PhpWord/Exceptions/InvalidObjectException.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Exceptions; diff --git a/src/PhpWord/Exceptions/InvalidStyleException.php b/src/PhpWord/Exceptions/InvalidStyleException.php index 3f39915e..9b22e0ae 100644 --- a/src/PhpWord/Exceptions/InvalidStyleException.php +++ b/src/PhpWord/Exceptions/InvalidStyleException.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Exceptions; diff --git a/src/PhpWord/Exceptions/UnsupportedImageTypeException.php b/src/PhpWord/Exceptions/UnsupportedImageTypeException.php index deb7a0f4..a2ea1ee9 100644 --- a/src/PhpWord/Exceptions/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exceptions/UnsupportedImageTypeException.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Exceptions; diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index aacca705..03247899 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/HashTable.php b/src/PhpWord/HashTable.php index accfb76f..97e9be45 100644 --- a/src/PhpWord/HashTable.php +++ b/src/PhpWord/HashTable.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 5c8771c2..6965e270 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index e617b74e..ec227d62 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 1fa0c4b8..e0506803 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -2,11 +2,9 @@ /** * PHPWord * - * PHP version 5.3 - * + * @link https://github.com/PHPOffice/PHPWord * @copyright 2014 PHPWord * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index d1418a54..e70bea94 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Reader; diff --git a/src/PhpWord/Reader/IReader.php b/src/PhpWord/Reader/IReader.php index 0629972d..a4bea94e 100644 --- a/src/PhpWord/Reader/IReader.php +++ b/src/PhpWord/Reader/IReader.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Reader; diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index cbfaf6dd..b5e679f2 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Reader; diff --git a/src/PhpWord/Section.php b/src/PhpWord/Section.php index 082c7e8b..168151b5 100644 --- a/src/PhpWord/Section.php +++ b/src/PhpWord/Section.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Section/Footer.php b/src/PhpWord/Section/Footer.php index 2589854e..6d87eabb 100755 --- a/src/PhpWord/Section/Footer.php +++ b/src/PhpWord/Section/Footer.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Footer/PreserveText.php b/src/PhpWord/Section/Footer/PreserveText.php index 5a94c3db..579ca271 100644 --- a/src/PhpWord/Section/Footer/PreserveText.php +++ b/src/PhpWord/Section/Footer/PreserveText.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section\Footer; diff --git a/src/PhpWord/Section/Footnote.php b/src/PhpWord/Section/Footnote.php index 4079812a..857c4e20 100644 --- a/src/PhpWord/Section/Footnote.php +++ b/src/PhpWord/Section/Footnote.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Header.php b/src/PhpWord/Section/Header.php index b023f175..154c9346 100755 --- a/src/PhpWord/Section/Header.php +++ b/src/PhpWord/Section/Header.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Image.php b/src/PhpWord/Section/Image.php index 931f906f..89b78ce7 100755 --- a/src/PhpWord/Section/Image.php +++ b/src/PhpWord/Section/Image.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Link.php b/src/PhpWord/Section/Link.php index d39c5459..39b1c56d 100644 --- a/src/PhpWord/Section/Link.php +++ b/src/PhpWord/Section/Link.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/ListItem.php b/src/PhpWord/Section/ListItem.php index 5394fc6f..3981814e 100644 --- a/src/PhpWord/Section/ListItem.php +++ b/src/PhpWord/Section/ListItem.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Object.php b/src/PhpWord/Section/Object.php index 487e6297..0988c20b 100644 --- a/src/PhpWord/Section/Object.php +++ b/src/PhpWord/Section/Object.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/PageBreak.php b/src/PhpWord/Section/PageBreak.php index d3f6d204..e12c3e3d 100644 --- a/src/PhpWord/Section/PageBreak.php +++ b/src/PhpWord/Section/PageBreak.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Settings.php b/src/PhpWord/Section/Settings.php index ea7504f3..2dbfe2d8 100644 --- a/src/PhpWord/Section/Settings.php +++ b/src/PhpWord/Section/Settings.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Table.php b/src/PhpWord/Section/Table.php index e0cee34e..aff9a23a 100644 --- a/src/PhpWord/Section/Table.php +++ b/src/PhpWord/Section/Table.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Table/Cell.php b/src/PhpWord/Section/Table/Cell.php index 5255ee4f..64dceab5 100755 --- a/src/PhpWord/Section/Table/Cell.php +++ b/src/PhpWord/Section/Table/Cell.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section\Table; diff --git a/src/PhpWord/Section/Table/Row.php b/src/PhpWord/Section/Table/Row.php index c81a0115..8410f571 100644 --- a/src/PhpWord/Section/Table/Row.php +++ b/src/PhpWord/Section/Table/Row.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2013 PhpWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section\Table; diff --git a/src/PhpWord/Section/Text.php b/src/PhpWord/Section/Text.php index 4c1caa29..a99945fe 100644 --- a/src/PhpWord/Section/Text.php +++ b/src/PhpWord/Section/Text.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/TextBreak.php b/src/PhpWord/Section/TextBreak.php index a9df1f54..97f6deca 100755 --- a/src/PhpWord/Section/TextBreak.php +++ b/src/PhpWord/Section/TextBreak.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/TextRun.php b/src/PhpWord/Section/TextRun.php index d6c2ea48..497f6f45 100755 --- a/src/PhpWord/Section/TextRun.php +++ b/src/PhpWord/Section/TextRun.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Section/Title.php b/src/PhpWord/Section/Title.php index 81628a88..c93f6687 100644 --- a/src/PhpWord/Section/Title.php +++ b/src/PhpWord/Section/Title.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Section; diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index c23e1093..6a648651 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 514a5c55..4c04a5fc 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 1abba078..23f368f6 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 08d6f6a5..262d3e42 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 26d037bc..c6bbafa9 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Shared/ZipStreamWrapper.php b/src/PhpWord/Shared/ZipStreamWrapper.php index 7e0369cd..b9eb5f32 100644 --- a/src/PhpWord/Shared/ZipStreamWrapper.php +++ b/src/PhpWord/Shared/ZipStreamWrapper.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index c88ae00b..f7b8e4c6 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index b88bcd0b..3949cddd 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 0b3df2ac..3ab855d6 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 30fa73f7..f2065a7e 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 1efd67fd..9c515e07 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 5f7ebbed..982aee44 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 0043c151..1ecb044b 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2013 PhpWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index d4019d0a..f1aa10bc 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 1d5092aa..8524143b 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 1dd36808..584f829e 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/Style/Tabs.php b/src/PhpWord/Style/Tabs.php index f0a5fcd6..343a2b35 100755 --- a/src/PhpWord/Style/Tabs.php +++ b/src/PhpWord/Style/Tabs.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index 1445ee17..865c6c38 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 635d5d6f..d952678e 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/Writer/IWriter.php b/src/PhpWord/Writer/IWriter.php index 2bafdd5b..ea69b830 100755 --- a/src/PhpWord/Writer/IWriter.php +++ b/src/PhpWord/Writer/IWriter.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 6f762608..98d0bcd1 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index fc3c53b0..44ac7bab 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 18e09440..f1c652ca 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index e30836e8..69cc5aea 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/ODText/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php index fa119136..0d4e598e 100644 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Mimetype.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 75a37915..f2d46c6a 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/ODText/WriterPart.php b/src/PhpWord/Writer/ODText/WriterPart.php index e61c758f..66531136 100644 --- a/src/PhpWord/Writer/ODText/WriterPart.php +++ b/src/PhpWord/Writer/ODText/WriterPart.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\ODText; diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 81f8e0eb..b9aa3aa3 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index fcd562ab..83bc7d21 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index d76d543d..0ebb7886 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 5971d8a8..ea97d138 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 9428a615..3c7d6977 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 00f2b7fa..ffce32d2 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 0996db4e..218869b5 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index 0ae8b9ea..a2ff09b4 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index d1545639..59d8cc1f 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index 9a9b53b0..7f87ce30 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 9ca69196..bdec8d45 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index d816b24e..a5f5084e 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index 799ff368..dc665300 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/src/PhpWord/Writer/Word2007/WriterPart.php b/src/PhpWord/Writer/Word2007/WriterPart.php index 01959437..2d7860e0 100755 --- a/src/PhpWord/Writer/Word2007/WriterPart.php +++ b/src/PhpWord/Writer/Word2007/WriterPart.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer\Word2007; diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index 5657fe6b..cd6d6488 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -1,8 +1,22 @@ Date: Thu, 27 Mar 2014 17:25:09 -0400 Subject: [PATCH 012/146] Get image dimensions without EXIF extension Use `getimagesize` when `exif_imagetype` doesn't exist. --- src/PhpWord/Section/Image.php | 7 ++++++- src/PhpWord/Writer/Word2007.php | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Section/Image.php b/src/PhpWord/Section/Image.php index 931f906f..ad625a7b 100755 --- a/src/PhpWord/Section/Image.php +++ b/src/PhpWord/Section/Image.php @@ -132,7 +132,12 @@ class Image throw new InvalidImageException; } $imgData = getimagesize($source); - $this->imageType = exif_imagetype($source); + if (function_exists('exif_imagetype')) { + $this->imageType = exif_imagetype($source); + } else { + $tmp = getimagesize($source); + $this->imageType = $tmp[2]; + } if (!in_array($this->imageType, $supportedTypes)) { throw new UnsupportedImageTypeException; } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index fcd562ab..33ff190c 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -270,7 +270,12 @@ class Word2007 implements IWriter if (stripos(strrev($src), strrev('.php')) === 0) { $extension = 'php'; } else { - $imageType = exif_imagetype($src); + if (function_exists('exif_imagetype')) { + $imageType = exif_imagetype($src); + } else { + $tmp = getimagesize($src); + $imageType = $tmp[2]; + } if ($imageType === \IMAGETYPE_JPEG) { $extension = 'jpg'; } elseif ($imageType === \IMAGETYPE_GIF) { From 2d178a672460e63c9c74b5f96b8cb6af17b165e5 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 28 Mar 2014 10:06:11 +0700 Subject: [PATCH 013/146] Update CHANGELOG.md --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bb699ea..30be78e6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. +## 0.9.2 - Not yet released + +### Features + +- Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 +- Table: Add tblGrid element for Libre/Open Office table sizing - @gianis6 GH-183 + +### Bugfixes + +- + +### Miscellaneous + +- Documentation: Simplify page level docblock - @ivanlanin GH-179 + ## 0.9.1 - 27 Mar 2014 This is a bugfix release for PSR-4 compatibility. From 88be3c962e1e29e560c46e476ce7300a0091f87c Mon Sep 17 00:00:00 2001 From: Louis Date: Fri, 28 Mar 2014 10:46:46 +0100 Subject: [PATCH 014/146] TOC Depth filter function added Add options to TOC to only show selected depth of titles ; ie pass 1,3 arguments to only show titles depth 1 to titles depth 3 Plus now you can have two+ TOC on your document, each different --- src/PhpWord/Section.php | 6 ++- src/PhpWord/TOC.php | 51 ++++++++++++++++++++++-- src/PhpWord/Writer/Word2007/Document.php | 16 +++++--- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/PhpWord/Section.php b/src/PhpWord/Section.php index 082c7e8b..f1937420 100644 --- a/src/PhpWord/Section.php +++ b/src/PhpWord/Section.php @@ -304,11 +304,13 @@ class Section * * @param mixed $styleFont * @param mixed $styleTOC + * @param int $minDepth + * @param int $maxDepth * @return \PhpOffice\PhpWord\TOC */ - public function addTOC($styleFont = null, $styleTOC = null) + public function addTOC($styleFont = null, $styleTOC = null, $minDepth = 1, $maxDepth = 9) { - $toc = new TOC($styleFont, $styleTOC); + $toc = new TOC($styleFont, $styleTOC, $minDepth, $maxDepth); $this->_elementCollection[] = $toc; return $toc; } diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index 1445ee17..ef5ddba0 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -67,6 +67,19 @@ class TOC */ private static $_bookmarkId = 0; + /** + * Min title depth to show + * + * @var int + */ + private $_minDepth = 1; + + /** + * Max title depth to show + * + * @var int + */ + private $_maxDepth = 9; /** * Create a new Table-of-Contents Element @@ -74,7 +87,7 @@ class TOC * @param array $styleFont * @param array $styleTOC */ - public function __construct($styleFont = null, $styleTOC = null) + public function __construct($styleFont = null, $styleTOC = null, $minDepth = 1, $maxDepth = 9) { self::$_styleTOC = new \PhpOffice\PhpWord\Style\TOC(); @@ -101,6 +114,9 @@ class TOC self::$_styleFont = $styleFont; } } + + $this->_minDepth = $minDepth; + $this->_maxDepth = $maxDepth; } /** @@ -131,9 +147,20 @@ class TOC * * @return array */ - public static function getTitles() + public function getTitles() { - return self::$_titles; + $titles = self::$_titles; + foreach ($titles as $i=>$title) { + if ($this->_minDepth > $title['depth']) { + unset($titles[$i]); + } + if (($this->_maxDepth != 0) && ($this->_maxDepth < $title['depth'])) { + unset($titles[$i]); + } + } + $titles = array_merge(array(), $titles); + + return $titles; } /** @@ -155,4 +182,22 @@ class TOC { return self::$_styleFont; } + + /** + * Get Max Depth + * + * @return int Max depth of titles + */ + public function getMaxDepth() { + return $this->_maxDepth; + } + + /** + * Get Min Depth + * + * @return int Min depth of titles + */ + public function getMinDepth() { + return $this->_minDepth; + } } diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 00f2b7fa..22cc8c0d 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -112,7 +112,7 @@ class Document extends Base } elseif ($element instanceof Object) { $this->_writeObject($xmlWriter, $element); } elseif ($element instanceof TOC) { - $this->_writeTOC($xmlWriter); + $this->_writeTOC($xmlWriter, $element); } elseif ($element instanceof Footnote) { $this->_writeFootnoteReference($xmlWriter, $element); } @@ -417,16 +417,20 @@ class Document extends Base * Write TOC element * * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param PhpOffice\PhpWord\TOC $toc */ - private function _writeTOC(XMLWriter $xmlWriter) + private function _writeTOC(XMLWriter $xmlWriter, TOC $toc) { - $titles = TOC::getTitles(); - $styleFont = TOC::getStyleFont(); + $titles = $toc->getTitles(); + $styleFont = $toc->getStyleFont(); - $styleTOC = TOC::getStyleTOC(); + $styleTOC = $toc->getStyleTOC(); $fIndent = $styleTOC->getIndent(); $tabLeader = $styleTOC->getTabLeader(); $tabPos = $styleTOC->getTabPos(); + + $maxDepth = $toc->getMaxDepth(); + $minDepth = $toc->getMinDepth(); $isObject = ($styleFont instanceof Font) ? true : false; @@ -479,7 +483,7 @@ class Document extends Base $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw('TOC \o "1-9" \h \z \u'); + $xmlWriter->writeRaw('TOC \o "'.$minDepth.'-'.$maxDepth.'" \h \z \u'); $xmlWriter->endElement(); $xmlWriter->endElement(); From 7a424318d29507d7ef2f22ae27239d68029c7616 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 28 Mar 2014 13:50:53 +0700 Subject: [PATCH 015/146] Unit tests enhancement --- license.md => LICENSE.md | 0 src/PhpWord/DocumentProperties.php | 5 +- src/PhpWord/Footnote.php | 7 +- src/PhpWord/Media.php | 9 +-- src/PhpWord/Section.php | 44 ++++------ src/PhpWord/Section/Footer.php | 2 +- src/PhpWord/Section/Header.php | 2 +- src/PhpWord/Section/Object.php | 2 +- src/PhpWord/Section/Table/Cell.php | 2 +- src/PhpWord/Shared/XMLWriter.php | 2 + src/PhpWord/Style/Table.php | 10 --- src/PhpWord/TOC.php | 21 +++-- tests/PhpWord/Tests/AutoloaderTest.php | 7 +- .../PhpWord/Tests/DocumentPropertiesTest.php | 40 +++++++++- tests/PhpWord/Tests/FootnoteTest.php | 35 ++++++++ tests/PhpWord/Tests/IOFactoryTest.php | 37 ++++++--- tests/PhpWord/Tests/MediaTest.php | 80 +++++++++++++++---- tests/PhpWord/Tests/PhpWordTest.php | 30 ------- tests/PhpWord/Tests/SectionTest.php | 80 +++++++++++-------- tests/PhpWord/Tests/SettingsTest.php | 4 +- tests/PhpWord/Tests/Style/FontTest.php | 30 ++++++- tests/PhpWord/Tests/Style/ParagraphTest.php | 11 +++ tests/PhpWord/Tests/Style/RowTest.php | 23 +++++- tests/PhpWord/Tests/Style/TableTest.php | 26 +++++- tests/PhpWord/Tests/StyleTest.php | 19 +++-- tests/PhpWord/Tests/TOCTest.php | 24 +++--- tests/PhpWord/Tests/TemplateTest.php | 14 +++- 27 files changed, 379 insertions(+), 187 deletions(-) rename license.md => LICENSE.md (100%) create mode 100644 tests/PhpWord/Tests/FootnoteTest.php diff --git a/license.md b/LICENSE.md similarity index 100% rename from license.md rename to LICENSE.md diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 188a417d..cc24e35a 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -436,13 +436,14 @@ class DocumentProperties */ public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null) { - if (($propertyType === null) || (!in_array($propertyType, array( + $propertyTypes = array( self::PROPERTY_TYPE_INTEGER, self::PROPERTY_TYPE_FLOAT, self::PROPERTY_TYPE_STRING, self::PROPERTY_TYPE_DATE, self::PROPERTY_TYPE_BOOLEAN - )))) { + ); + if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) { if ($propertyValue === null) { $propertyType = self::PROPERTY_TYPE_STRING; } elseif (is_float($propertyValue)) { diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 03247899..69228ee8 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -31,10 +31,7 @@ class Footnote /** * Add new Footnote Element * - * @param string $linkSrc - * @param string $linkName - * - * @return mixed + * @return int Reference ID */ public static function addFootnoteElement(\PhpOffice\PhpWord\Section\Footnote $footnote) { @@ -70,7 +67,7 @@ class Footnote * * @param string $linkSrc * - * @return mixed + * @return int Reference ID */ public static function addFootnoteLinkElement($linkSrc) { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index ec227d62..80cde281 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -69,11 +69,10 @@ class Media $file = null; if ($type === 'image') { $cImg++; + $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); $extension = $image->getImageExtension(); - } else { - $isMemImage = false; } if ($isMemImage) { $media['isMemImage'] = true; @@ -181,11 +180,10 @@ class Media $rID = $cImg + 1; $cImg++; $media = array(); + $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); $extension = $image->getImageExtension(); - } else { - $isMemImage = false; } if ($isMemImage) { $media['isMemImage'] = true; @@ -244,11 +242,10 @@ class Media $cImg = self::countFooterMediaElements($key); $rID = $cImg + 1; $cImg++; + $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); $extension = $image->getImageExtension(); - } else { - $isMemImage = false; } if ($isMemImage) { $media['isMemImage'] = true; diff --git a/src/PhpWord/Section.php b/src/PhpWord/Section.php index 168151b5..320708c9 100644 --- a/src/PhpWord/Section.php +++ b/src/PhpWord/Section.php @@ -9,7 +9,6 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; use PhpOffice\PhpWord\Exceptions\InvalidObjectException; use PhpOffice\PhpWord\Section\Footer; use PhpOffice\PhpWord\Section\Image; @@ -211,72 +210,61 @@ class Section /** * Add a OLE-Object Element * + * All exceptions should be handled by PhpOffice\PhpWord\Section\Object + * * @param string $src * @param mixed $style * @return \PhpOffice\PhpWord\Section\Object - * @throws \PhpOffice\PhpWord\Exceptions\InvalidObjectException */ public function addObject($src, $style = null) { $object = new Object($src, $style); - if (!is_null($object->getSource())) { $inf = pathinfo($src); $ext = $inf['extension']; if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { $ext = substr($ext, 0, -1); } - - $iconSrc = __DIR__ . '/_staticDocParts/'; - if (!\file_exists($iconSrc . '_' . $ext . '.png')) { - $iconSrc = $iconSrc . '_default.png'; - } else { - $iconSrc .= '_' . $ext . '.png'; - } - - $rIDimg = Media::addSectionMediaElement($iconSrc, 'image', new Image($iconSrc)); + $icon = __DIR__ . "/_staticDocParts/_{$ext}.png"; + $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); $data = Media::addSectionMediaElement($src, 'oleObject'); $rID = $data[0]; $objectId = $data[1]; - $object->setRelationId($rID); $object->setObjectId($objectId); $object->setImageRelationId($rIDimg); - $this->_elementCollection[] = $object; return $object; } else { - throw new InvalidObjectException; + throw new InvalidObjectException(); } } /** - * Add a Image Element + * Add image element + * + * All exceptions should be handled by PhpOffice\PhpWord\Section\Image * * @param string $src * @param mixed $style * @return \PhpOffice\PhpWord\Section\Image - * @throws \PhpOffice\PhpWord\Exceptions\InvalidImageException */ public function addImage($src, $style = null) { $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addSectionMediaElement($src, 'image', $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } + $rID = Media::addSectionMediaElement($src, 'image', $image); + $image->setRelationId($rID); + $this->_elementCollection[] = $image; + return $image; } /** - * Add a by PHP created Image Element + * Add memory image element * - * @param string $link - * @param mixed $style * @deprecated + * + * @param string $src + * @param mixed $style */ public function addMemoryImage($src, $style = null) { diff --git a/src/PhpWord/Section/Footer.php b/src/PhpWord/Section/Footer.php index 6d87eabb..58c439d2 100755 --- a/src/PhpWord/Section/Footer.php +++ b/src/PhpWord/Section/Footer.php @@ -131,7 +131,7 @@ class Footer /** * Add a by PHP created Image Element * - * @param string $link + * @param string $src * @param mixed $style * @deprecated */ diff --git a/src/PhpWord/Section/Header.php b/src/PhpWord/Section/Header.php index 154c9346..5a89c266 100755 --- a/src/PhpWord/Section/Header.php +++ b/src/PhpWord/Section/Header.php @@ -160,7 +160,7 @@ class Header /** * Add a by PHP created Image Element * - * @param string $link + * @param string $src * @param mixed $style * @deprecated */ diff --git a/src/PhpWord/Section/Object.php b/src/PhpWord/Section/Object.php index 0988c20b..9b6cc328 100644 --- a/src/PhpWord/Section/Object.php +++ b/src/PhpWord/Section/Object.php @@ -58,7 +58,7 @@ class Object */ public function __construct($src, $style = null) { - $_supportedObjectTypes = array('xls', 'doc', 'ppt'); + $_supportedObjectTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'); $inf = pathinfo($src); if (\file_exists($src) && in_array($inf['extension'], $_supportedObjectTypes)) { diff --git a/src/PhpWord/Section/Table/Cell.php b/src/PhpWord/Section/Table/Cell.php index 64dceab5..601f6030 100755 --- a/src/PhpWord/Section/Table/Cell.php +++ b/src/PhpWord/Section/Table/Cell.php @@ -205,7 +205,7 @@ class Cell /** * Add a by PHP created Image Element * - * @param string $link + * @param string $src * @param mixed $style * @deprecated */ diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index c6bbafa9..5b21e7b1 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -11,9 +11,11 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; +// @codeCoverageIgnoreStart if (!defined('DATE_W3C')) { define('DATE_W3C', 'Y-m-d\TH:i:sP'); } +// @codeCoverageIgnoreEnd /** * XMLWriter wrapper diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 584f829e..b6de4a81 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -208,16 +208,6 @@ class Table return $this->_firstRow; } - /** - * Get Last Row Style - * - * @return \PhpOffice\PhpWord\Style\Table - */ - public function getLastRow() - { - return $this->_lastRow; - } - /** * Get background * diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index 865c6c38..e6a24234 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -17,37 +17,37 @@ use PhpOffice\PhpWord\Style\Font; class TOC { /** - * Title Elements + * Title elements * * @var array */ private static $_titles = array(); /** - * TOC Style + * TOC style * - * @var array + * @var PhpOffice\PhpWord\Style\TOC */ private static $_styleTOC; /** - * Font Style + * Font style * - * @var array + * @var PhpOffice\PhpWord\Style\Font|array|string */ private static $_styleFont; /** - * Title Anchor + * Title anchor * - * @var array + * @var int */ private static $_anchor = 252634154; /** - * Title Bookmark + * Title bookmark * - * @var array + * @var int */ private static $_bookmarkId = 0; @@ -55,7 +55,7 @@ class TOC /** * Create a new Table-of-Contents Element * - * @param array $styleFont + * @param mixed $styleFont * @param array $styleTOC */ public function __construct($styleFont = null, $styleTOC = null) @@ -74,7 +74,6 @@ class TOC if (!is_null($styleFont)) { if (is_array($styleFont)) { self::$_styleFont = new Font(); - foreach ($styleFont as $key => $value) { if (substr($key, 0, 1) != '_') { $key = '_' . $key; diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index cd6d6488..549f05a8 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Autoloader; /** * Test class for PhpOffice\PhpWord\Autoloader * - * @coversDefaultClass \PhpOffice\PhpWord\Autoloader * @runTestsInSeparateProcesses */ class AutoloaderTest extends \PHPUnit_Framework_TestCase { + /** + * Register + */ public function testRegister() { Autoloader::register(); @@ -28,6 +30,9 @@ class AutoloaderTest extends \PHPUnit_Framework_TestCase ); } + /** + * Autoload + */ public function testAutoload() { $declared = \get_declared_classes(); diff --git a/tests/PhpWord/Tests/DocumentPropertiesTest.php b/tests/PhpWord/Tests/DocumentPropertiesTest.php index a6181f8c..207eb195 100644 --- a/tests/PhpWord/Tests/DocumentPropertiesTest.php +++ b/tests/PhpWord/Tests/DocumentPropertiesTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\DocumentProperties; /** * Test class for PhpOffice\PhpWord\DocumentProperties * - * @coversDefaultClass \PhpOffice\PhpWord\DocumentProperties * @runTestsInSeparateProcesses */ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase { + /** + * Creator + */ public function testCreator() { $oProperties = new DocumentProperties(); @@ -29,6 +31,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getCreator()); } + /** + * Last modified by + */ public function testLastModifiedBy() { $oProperties = new DocumentProperties(); @@ -39,6 +44,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getLastModifiedBy()); } + /** + * Created + */ public function testCreated() { $oProperties = new DocumentProperties(); @@ -50,6 +58,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iTime, $oProperties->getCreated()); } + /** + * Modified + */ public function testModified() { $oProperties = new DocumentProperties(); @@ -61,6 +72,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iTime, $oProperties->getModified()); } + /** + * Title + */ public function testTitle() { $oProperties = new DocumentProperties(); @@ -71,6 +85,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getTitle()); } + /** + * Description + */ public function testDescription() { $oProperties = new DocumentProperties(); @@ -81,6 +98,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getDescription()); } + /** + * Subject + */ public function testSubject() { $oProperties = new DocumentProperties(); @@ -91,6 +111,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getSubject()); } + /** + * Keywords + */ public function testKeywords() { $oProperties = new DocumentProperties(); @@ -101,6 +124,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getKeywords()); } + /** + * Category + */ public function testCategory() { $oProperties = new DocumentProperties(); @@ -111,6 +137,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getCategory()); } + /** + * Company + */ public function testCompany() { $oProperties = new DocumentProperties(); @@ -121,6 +150,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getCompany()); } + /** + * Manager + */ public function testManager() { $oProperties = new DocumentProperties(); @@ -131,6 +163,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getManager()); } + /** + * Custom properties + */ public function testCustomProperty() { $oProperties = new DocumentProperties(); @@ -177,6 +212,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase ), $oProperties->getCustomProperties()); } + /** + * Convert property + */ public function testConvertProperty() { $this->assertEquals('', DocumentProperties::convertProperty('a', 'empty')); diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php new file mode 100644 index 00000000..79bb75ad --- /dev/null +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -0,0 +1,35 @@ +assertEquals(2, $rIdFootnote); + $this->assertEquals(1, $rIdLink); + $this->assertEquals(1, count(Footnote::getFootnoteElements())); + $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); + } +} diff --git a/tests/PhpWord/Tests/IOFactoryTest.php b/tests/PhpWord/Tests/IOFactoryTest.php index 8e9cf3fe..bb2a6530 100644 --- a/tests/PhpWord/Tests/IOFactoryTest.php +++ b/tests/PhpWord/Tests/IOFactoryTest.php @@ -15,15 +15,14 @@ use PhpOffice\PhpWord\IOFactory; /** * Test class for PhpOffice\PhpWord\IOFactory * - * @coversDefaultClass \PhpOffice\PhpWord\IOFactory * @runTestsInSeparateProcesses */ -final class IOFactoryTest extends \PHPUnit_Framework_TestCase +class IOFactoryTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::createWriter + * Create existing writer */ - final public function testExistingWriterCanBeCreated() + public function testExistingWriterCanBeCreated() { $this->assertInstanceOf( 'PhpOffice\\PhpWord\\Writer\\Word2007', @@ -32,18 +31,19 @@ final class IOFactoryTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::createWriter - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Create non-existing writer + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ - final public function testNonexistentWriterCanNotBeCreated() + public function testNonexistentWriterCanNotBeCreated() { IOFactory::createWriter(new PhpWord(), 'Word2006'); } /** - * @covers ::createReader + * Create existing reader */ - final public function testExistingReaderCanBeCreated() + public function testExistingReaderCanBeCreated() { $this->assertInstanceOf( 'PhpOffice\\PhpWord\\Reader\\Word2007', @@ -52,11 +52,24 @@ final class IOFactoryTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::createReader - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Create non-existing reader + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ - final public function testNonexistentReaderCanNotBeCreated() + public function testNonexistentReaderCanNotBeCreated() { IOFactory::createReader('Word2006'); } + + /** + * Load document + */ + public function testLoad() + { + $file = __DIR__ . "/_files/templates/blank.docx"; + $this->assertInstanceOf( + 'PhpOffice\\PhpWord\\PhpWord', + IOFactory::load($file) + ); + } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index d3cbb9c2..ac5aafbd 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -11,25 +11,34 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Section\Image; /** * Test class for PhpOffice\PhpWord\Media * - * @coversDefaultClass \PhpOffice\PhpWord\Media * @runTestsInSeparateProcesses */ class MediaTest extends \PHPUnit_Framework_TestCase { + /** + * Get section media elements + */ public function testGetSectionMediaElementsWithNull() { $this->assertEquals(Media::getSectionMediaElements(), array()); } + /** + * Count section media elements + */ public function testCountSectionMediaElementsWithNull() { $this->assertEquals(Media::countSectionMediaElements(), 0); } + /** + * Get header media elements + */ public function testGetHeaderMediaElements() { $this->assertAttributeEquals( @@ -39,6 +48,9 @@ class MediaTest extends \PHPUnit_Framework_TestCase ); } + /** + * Get footer media elements + */ public function testGetFooterMediaElements() { $this->assertAttributeEquals( @@ -49,24 +61,60 @@ class MediaTest extends \PHPUnit_Framework_TestCase } /** - * Todo: add memory image to this test - * - * @covers \PhpOffice\PhpWord\Media::addSectionMediaElement + * Add section media element */ public function testAddSectionMediaElement() { - $section = new Section(0); - $section->addImage(__DIR__ . "/_files/images/mars_noext_jpg"); - $section->addImage(__DIR__ . "/_files/images/mars.jpg"); - $section->addImage(__DIR__ . "/_files/images/mario.gif"); - $section->addImage(__DIR__ . "/_files/images/firefox.png"); - $section->addImage(__DIR__ . "/_files/images/duke_nukem.bmp"); - $section->addImage(__DIR__ . "/_files/images/angela_merkel.tif"); + $local = __DIR__ . "/_files/images/mars.jpg"; + $object = __DIR__ . "/_files/documents/sheet.xls"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addSectionMediaElement($local, 'image'); + Media::addSectionMediaElement($local, 'image'); + Media::addSectionMediaElement($remote, 'image', new Image($remote)); + Media::addSectionMediaElement($object, 'oleObject'); + Media::addSectionMediaElement($object, 'oleObject'); - $elements = $section->getElements(); - $this->assertEquals(6, count($elements)); - foreach ($elements as $element) { - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); - } + $this->assertEquals(3, Media::countSectionMediaElements()); + } + + /** + * Add section link + */ + public function testAddSectionLinkElement() + { + $expected = Media::countSectionMediaElements() + 7; + $actual = Media::addSectionLinkElement('http://test.com'); + + $this->assertEquals($expected, $actual); + $this->assertEquals(1, Media::countSectionMediaElements('links')); + $this->assertEquals(1, count(Media::getSectionMediaElements('links'))); + } + + /** + * Add header media element + */ + public function testAddHeaderMediaElement() + { + $local = __DIR__ . "/_files/images/mars.jpg"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addHeaderMediaElement(1, $local); + Media::addHeaderMediaElement(1, $local); + Media::addHeaderMediaElement(1, $remote, new Image($remote)); + + $this->assertEquals(2, Media::countHeaderMediaElements('header1')); + } + + /** + * Add footer media element + */ + public function testAddFooterMediaElement() + { + $local = __DIR__ . "/_files/images/mars.jpg"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addFooterMediaElement(1, $local); + Media::addFooterMediaElement(1, $local); + Media::addFooterMediaElement(1, $remote, new Image($remote)); + + $this->assertEquals(2, Media::countFooterMediaElements('footer1')); } } diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 3c15f746..500d46c8 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -17,17 +17,12 @@ use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\PhpWord * - * @coversDefaultClass \PhpOffice\PhpWord\PhpWord * @runTestsInSeparateProcesses */ class PhpWordTest extends \PHPUnit_Framework_TestCase { /** * Test object creation - * - * @covers ::getDocumentProperties - * @covers ::getDefaultFontName - * @covers ::getDefaultFontSize */ public function testConstruct() { @@ -39,9 +34,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test set/get document properties - * - * @covers ::setDocumentProperties - * @covers ::getDocumentProperties */ public function testSetGetDocumentProperties() { @@ -55,9 +47,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test create/get section - * - * @covers ::createSection - * @covers ::getSections */ public function testCreateGetSections() { @@ -69,9 +58,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test set/get default font name - * - * @covers ::setDefaultFontName - * @covers ::getDefaultFontName */ public function testSetGetDefaultFontName() { @@ -84,9 +70,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test set/get default font size - * - * @covers ::setDefaultFontSize - * @covers ::getDefaultFontSize */ public function testSetGetDefaultFontSize() { @@ -99,9 +82,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test set default paragraph style - * - * @covers ::setDefaultParagraphStyle - * @covers ::loadTemplate */ public function testSetDefaultParagraphStyle() { @@ -112,11 +92,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test add styles - * - * @covers ::addParagraphStyle - * @covers ::addFontStyle - * @covers ::addTableStyle - * @covers ::addLinkStyle */ public function testAddStyles() { @@ -138,8 +113,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test add title style - * - * @covers ::addTitleStyle */ public function testAddTitleStyle() { @@ -152,8 +125,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test load template - * - * @covers ::loadTemplate */ public function testLoadTemplate() { @@ -169,7 +140,6 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test load template exception * - * @covers ::loadTemplate * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ public function testLoadTemplateException() diff --git a/tests/PhpWord/Tests/SectionTest.php b/tests/PhpWord/Tests/SectionTest.php index 22553c45..448361ab 100644 --- a/tests/PhpWord/Tests/SectionTest.php +++ b/tests/PhpWord/Tests/SectionTest.php @@ -10,17 +10,17 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Section * - * @coversDefaultClass \PhpOffice\PhpWord\Section * @runTestsInSeparateProcesses */ class SectionTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::getSettings + * Get settings */ public function testGetSettings() { @@ -29,7 +29,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getElements + * Get elements */ public function testGetElements() { @@ -38,7 +38,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getFooter + * Get footer */ public function testGetFooter() { @@ -47,7 +47,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getHeaders + * Get headers */ public function testGetHeaders() { @@ -56,7 +56,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setSettings + * Set settings */ public function testSetSettings() { @@ -67,22 +67,11 @@ class SectionTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::addText - * @covers ::addLink - * @covers ::addTextBreak - * @covers ::addPageBreak - * @covers ::addTable - * @covers ::addListItem - * @covers ::addObject - * @covers ::addImage - * @covers ::addTOC - * @covers ::addTitle - * @covers ::createTextRun - * @covers ::createFootnote + * Add elements */ public function testAddElements() { - $objectSource = __DIR__ . "/_files/documents/sheet.xls"; + $objectSource = __DIR__ . "/_files/documents/reader.docx"; $imageSource = __DIR__ . "/_files/images/PhpWord.png"; $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; @@ -95,36 +84,61 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section->addListItem(utf8_decode('ä')); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addImage($imageUrl); - $section->addTOC(); + $section->addMemoryImage($imageUrl); $section->addTitle(utf8_decode('ä'), 1); $section->createTextRun(); $section->createFootnote(); + $section->addTOC(); $elementCollection = $section->getElements(); - $elementType = 'Link'; - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[1]); - // $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', - // 'Table', 'ListItem', 'Object', 'Image', 'Image', 'TOC', - // 'Title', 'TextRun'); - // $i = 0; - // foreach ($elementTypes as $elementType) { - // $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[$i]); - // $i++; - // } + $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', + 'Table', 'ListItem', 'Object', 'Image', 'Image', + 'Title', 'TextRun', 'Footnote'); + $i = 0; + foreach ($elementTypes as $elementType) { + $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[$i]); + $i++; + } + $this->assertInstanceOf("PhpOffice\\PhpWord\\TOC", $elementCollection[$i]); } /** - * @covers ::createHeader - * @covers ::createFooter + * Test add object exception + * + * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidObjectException + */ + public function testAddObjectException() + { + $source = __DIR__ . "/_files/xsl/passthrough.xsl"; + $section = new Section(0); + $section->addObject($source); + } + + /** + * Add title with predefined style + */ + public function testAddTitleWithStyle() + { + Style::addTitleStyle(1, array('size' => 14)); + $section = new Section(0); + $section->addTitle('Test', 1); + $elementCollection = $section->getElements(); + + $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\Title", $elementCollection[0]); + } + + /** + * Create header footer */ public function testCreateHeaderFooter() { $object = new Section(0); $elements = array('Header', 'Footer'); + foreach ($elements as $element) { $method = "create{$element}"; $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$element}", $object->$method()); } + $this->assertFalse($object->hasDifferentFirstPage()); } } diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index c70e7a7f..543da143 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -14,14 +14,12 @@ use PhpOffice\PhpWord\Settings; /** * Test class for PhpOffice\PhpWord\Settings * - * @coversDefaultClass \PhpOffice\PhpWord\Settings * @runTestsInSeparateProcesses */ class SettingsTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::setCompatibility - * @covers ::getCompatibility + * Get and set compatibity option */ public function testGetSetCompatibility() { diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 79aadbd3..482bfe91 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -55,6 +55,7 @@ class FontTest extends \PHPUnit_Framework_TestCase 'strikethrough' => false, 'color' => PhpWord::DEFAULT_FONT_COLOR, 'fgColor' => null, + 'hint' => PhpWord::DEFAULT_FONT_CONTENT_TYPE, ); foreach ($attributes as $key => $default) { $get = "get{$key}"; @@ -78,19 +79,23 @@ class FontTest extends \PHPUnit_Framework_TestCase 'bold' => true, 'italic' => true, 'superScript' => true, - 'subScript' => true, + 'subScript' => false, 'underline' => Font::UNDERLINE_HEAVY, 'strikethrough' => true, 'color' => '999999', 'fgColor' => '999999', + 'hint' => 'eastAsia', ); + $object->setArrayStyle($attributes); foreach ($attributes as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_$key", $value); $this->assertEquals($value, $object->$get()); } } + /** + * Test set line height + */ public function testLineHeight() { $phpWord = new PhpWord(); @@ -121,4 +126,25 @@ class FontTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $lineHeight); $this->assertEquals('auto', $lineRule); } + + /** + * Test line height floatval + */ + public function testLineHeightFloatval() + { + $object = new Font(null, array('align' => 'center')); + $object->setLineHeight('1.5pt'); + $this->assertEquals(1.5, $object->getLineHeight()); + } + + /** + * Test line height exception by using nonnumeric value + * + * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException + */ + public function testLineHeightException() + { + $object = new Font(); + $object->setLineHeight('a'); + } } diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index ca6aa700..856e2b13 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -137,4 +137,15 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase $object->setLineHeight('12.5pt'); $this->assertEquals(12.5, $object->getLineHeight()); } + + /** + * Test line height exception by using nonnumeric value + * + * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException + */ + public function testLineHeightException() + { + $object = new Paragraph(); + $object->setLineHeight('a'); + } } diff --git a/tests/PhpWord/Tests/Style/RowTest.php b/tests/PhpWord/Tests/Style/RowTest.php index c20320c0..daf27efb 100644 --- a/tests/PhpWord/Tests/Style/RowTest.php +++ b/tests/PhpWord/Tests/Style/RowTest.php @@ -20,9 +20,9 @@ use PhpOffice\PhpWord\Style\Row; class RowTest extends \PHPUnit_Framework_TestCase { /** - * Test properties with normal value + * Test properties with boolean value */ - public function testProperties() + public function testBooleanValue() { $object = new Row(); @@ -45,4 +45,23 @@ class RowTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, $object->$get()); } } + + /** + * Test properties with nonboolean values, which will return default value + */ + public function testNonBooleanValue() + { + $object = new Row(); + + $properties = array( + 'tblHeader' => 'a', + 'cantSplit' => 'b', + ); + foreach ($properties as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertFalse($object->$get()); + } + } } diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index 2b97d132..a193f43d 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -14,7 +14,6 @@ use PhpOffice\PhpWord\Style\Table; /** * Test class for PhpOffice\PhpWord\Style\Table * - * @coversDefaultClass \PhpOffice\PhpWord\Style\Table * @runTestsInSeparateProcesses */ class TableTest extends \PHPUnit_Framework_TestCase @@ -25,7 +24,6 @@ class TableTest extends \PHPUnit_Framework_TestCase * There are 3 variables for class constructor: * - $styleTable: Define table styles * - $styleFirstRow: Define style for the first row - * - $styleLastRow: Define style for the last row (reserved) */ public function testConstruct() { @@ -138,4 +136,28 @@ class TableTest extends \PHPUnit_Framework_TestCase } $this->assertEquals($values, $object->getCellMargin()); } + + /** + * Set style value for various special value types + */ + public function testSetStyleValue() + { + $object = new Table(); + $object->setStyleValue('_borderSize', 120); + $object->setStyleValue('_cellMargin', 240); + $object->setStyleValue('_borderColor', '999999'); + + $this->assertEquals( + array(120, 120, 120, 120, 120, 120), + $object->getBorderSize() + ); + $this->assertEquals( + array(240, 240, 240, 240), + $object->getCellMargin() + ); + $this->assertEquals( + array('999999', '999999', '999999', '999999', '999999', '999999'), + $object->getBorderColor() + ); + } } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index e400d3fd..6381cbc9 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -14,16 +14,12 @@ use PhpOffice\PhpWord\Style; /** * Test class for PhpOffice\PhpWord\Style * - * @coversDefaultClass \PhpOffice\PhpWord\Style * @runTestsInSeparateProcesses */ class StyleTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::addParagraphStyle - * @covers ::addFontStyle - * @covers ::addLinkStyle - * @covers ::addTitleStyle + * Add and get paragraph, font, link, title, and table styles */ public function testStyles() { @@ -34,6 +30,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase 'Link' => 'Font', 'Table' => 'Table', 'Heading_1' => 'Font', 'Normal' => 'Paragraph'); $elementCount = 6; + Style::addParagraphStyle('Paragraph', $paragraph); Style::addFontStyle('Font', $font); Style::addLinkStyle('Link', $font); @@ -47,4 +44,16 @@ class StyleTest extends \PHPUnit_Framework_TestCase } $this->assertNull(Style::getStyle('Unknown')); } + + /** + * Set default paragraph style + */ + public function testDefaultParagraphStyle() + { + $paragraph = array('align' => 'center'); + + Style::setDefaultParagraphStyle($paragraph); + + $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\Paragraph", Style::getStyle('Normal')); + } } diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 3764a161..100206a4 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -14,17 +14,14 @@ use PhpOffice\PhpWord\TOC; /** * Test class for PhpOffice\PhpWord\TOC * - * @coversDefaultClass \PhpOffice\PhpWord\TOC * @runTestsInSeparateProcesses */ class TOCTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::__construct - * @covers ::getStyleTOC - * @covers ::getStyleFont + * Construct with font and TOC style in array format */ - public function testConstruct() + public function testConstructWithStyleArray() { $expected = array( 'tabPos' => 9062, @@ -44,12 +41,21 @@ class TOCTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::addTitle - * @covers ::getTitles + * Construct with named font style + */ + public function testConstructWithStyleName() + { + $object = new TOC('Font Style'); + $tocStyle = $object->getStyleTOC(); + + $this->assertEquals('Font Style', $object->getStyleFont()); + } + + /** + * Add and get title */ public function testAddAndGetTitle() { - // Prepare variables $titleCount = 3; $anchor = '_Toc' . (252634154 + $titleCount); $bookmark = $titleCount - 1; @@ -59,14 +65,12 @@ class TOCTest extends \PHPUnit_Framework_TestCase 'Heading 3' => 3, ); - // @covers ::addTitle foreach ($titles as $text => $depth) { $response = TOC::addTitle($text, $depth); } $this->assertEquals($anchor, $response[0]); $this->assertEquals($bookmark, $response[1]); - // @covers ::getTitles $i = 0; $savedTitles = TOC::getTitles(); foreach ($titles as $text => $depth) { diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index f91368e8..b9302f7e 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -15,12 +15,15 @@ use PhpOffice\PhpWord\Template; /** * Test class for PhpOffice\PhpWord\Template * + * @covers \PhpOffice\PhpWord\Template * @coversDefaultClass \PhpOffice\PhpWord\Template * @runTestsInSeparateProcesses */ final class TemplateTest extends \PHPUnit_Framework_TestCase { /** + * Template can be saved in temporary location + * * @covers ::save * @test */ @@ -60,6 +63,8 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase } /** + * XSL stylesheet can be applied + * * @covers ::applyXslStyleSheet * @depends testTemplateCanBeSavedInTemporaryLocation * @test @@ -86,6 +91,8 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase } /** + * XSL stylesheet cannot be applied on failure in setting parameter value + * * @covers ::applyXslStyleSheet * @expectedException \PhpOffice\PhpWord\Exceptions\Exception * @expectedExceptionMessage Could not set values for the given XSL style sheet parameters. @@ -106,6 +113,8 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase } /** + * XSL stylesheet can be applied on failure of loading XML from template + * * @covers ::applyXslStyleSheet * @expectedException \PhpOffice\PhpWord\Exceptions\Exception * @expectedExceptionMessage Could not load XML from the given template. @@ -126,10 +135,7 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getVariables - * @covers ::setValue - * @covers ::cloneRow - * @covers ::saveAs + * Get variables and clone row */ public function testCloneRow() { From 92588ccfd952836a1568b3474c756ff2558322af Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 28 Mar 2014 19:25:12 +0700 Subject: [PATCH 016/146] Fix variable for MediaTest --- tests/PhpWord/Tests/MediaTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index ac5aafbd..62ce56a9 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -68,8 +68,8 @@ class MediaTest extends \PHPUnit_Framework_TestCase $local = __DIR__ . "/_files/images/mars.jpg"; $object = __DIR__ . "/_files/documents/sheet.xls"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addSectionMediaElement($local, 'image'); - Media::addSectionMediaElement($local, 'image'); + Media::addSectionMediaElement($local, 'image', new Image($local)); + Media::addSectionMediaElement($local, 'image', new Image($local)); Media::addSectionMediaElement($remote, 'image', new Image($remote)); Media::addSectionMediaElement($object, 'oleObject'); Media::addSectionMediaElement($object, 'oleObject'); @@ -97,8 +97,8 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addHeaderMediaElement(1, $local); - Media::addHeaderMediaElement(1, $local); + Media::addHeaderMediaElement(1, $local, new Image($local)); + Media::addHeaderMediaElement(1, $local, new Image($local)); Media::addHeaderMediaElement(1, $remote, new Image($remote)); $this->assertEquals(2, Media::countHeaderMediaElements('header1')); @@ -111,8 +111,8 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addFooterMediaElement(1, $local); - Media::addFooterMediaElement(1, $local); + Media::addFooterMediaElement(1, $local, new Image($local)); + Media::addFooterMediaElement(1, $local, new Image($local)); Media::addFooterMediaElement(1, $remote, new Image($remote)); $this->assertEquals(2, Media::countFooterMediaElements('footer1')); From 8363ee27d1461177dd625974f43feb1c160eb6ba Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Fri, 28 Mar 2014 13:26:36 -0400 Subject: [PATCH 017/146] table row height rule moved to rowStyle (ivanlanin) new usage: $table->addRow($height, array("heightRule"=>"exact")); Signed-off-by: Julien Carignan --- Classes/PHPWord/Section/Table.php | 4 +-- Classes/PHPWord/Section/Table/Row.php | 20 +-------------- Classes/PHPWord/Style/Row.php | 32 ++++++++++++++++++++++++ Classes/PHPWord/Writer/Word2007/Base.php | 8 +++--- samples/Sample_21_TableRowRules.php | 11 +++++--- 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/Classes/PHPWord/Section/Table.php b/Classes/PHPWord/Section/Table.php index 7efdf0b8..80126cba 100755 --- a/Classes/PHPWord/Section/Table.php +++ b/Classes/PHPWord/Section/Table.php @@ -101,9 +101,9 @@ class PHPWord_Section_Table * @param int $height * @param mixed $style */ - public function addRow($height = null, $style = null, $hRules = null) + public function addRow($height = null, $style = null) { - $row = new PHPWord_Section_Table_Row($this->_insideOf, $this->_pCount, $height, $style, $hRules); + $row = new PHPWord_Section_Table_Row($this->_insideOf, $this->_pCount, $height, $style); $this->_rows[] = $row; return $row; } diff --git a/Classes/PHPWord/Section/Table/Row.php b/Classes/PHPWord/Section/Table/Row.php index 5b239c89..7ca99823 100644 --- a/Classes/PHPWord/Section/Table/Row.php +++ b/Classes/PHPWord/Section/Table/Row.php @@ -38,13 +38,6 @@ class PHPWord_Section_Table_Row */ private $_height = null; - /** - * Row heightRules - * - * @var array - */ - private $_heightRules = array(); - /** * Row style * @@ -82,12 +75,11 @@ class PHPWord_Section_Table_Row * @param int $height * @param mixed $style */ - public function __construct($insideOf, $pCount, $height = null, $style = null, $hRules = null) + public function __construct($insideOf, $pCount, $height = null, $style = null) { $this->_insideOf = $insideOf; $this->_pCount = $pCount; $this->_height = $height; - $this->_heightRules = $hRules; $this->_style = new PHPWord_Style_Row(); if (!is_null($style)) { @@ -146,14 +138,4 @@ class PHPWord_Section_Table_Row { return $this->_height; } - - /** - * Get all row height rules - * - * @return array - */ - public function getHeightRules() - { - return $this->_heightRules; - } } diff --git a/Classes/PHPWord/Style/Row.php b/Classes/PHPWord/Style/Row.php index da039d84..aae7e851 100644 --- a/Classes/PHPWord/Style/Row.php +++ b/Classes/PHPWord/Style/Row.php @@ -45,6 +45,13 @@ class PHPWord_Style_Row */ private $_cantSplit = false; + /** + * Table row height rule (auto, exact, atLeast) + * + * @var String + */ + private $_heightRule = null; + /** * Create a new row style */ @@ -112,4 +119,29 @@ class PHPWord_Style_Row { return $this->_cantSplit; } + + /** + * Set heightRule + * + * @param String $pValue + * @return PHPWord_Style_Row + */ + public function setHeightRule($pValue = false) + { + if (!is_string($pValue)) { + $pValue = null; + } + $this->_heightRule = $pValue; + return $this; + } + + /** + * Get heightRule + * + * @return heightRule + */ + public function getHeightRule() + { + return $this->_heightRule; + } } diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index 57bb7266..0a45fb20 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -569,11 +569,11 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart for ($i = 0; $i < $_cRows; $i++) { $row = $_rows[$i]; - $height = $row->getHeight(); - $heightRules = $row->getHeightRules(); + $height = $row->getHeight(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $cantSplit = $rowStyle->getCantSplit(); + $heightRule = $rowStyle->getHeightRule(); $objWriter->startElement('w:tr'); @@ -581,9 +581,9 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $objWriter->startElement('w:trPr'); if (!is_null($height)) { $objWriter->startElement('w:trHeight'); - if(!is_null($heightRules)) { + if(!is_null($heightRule)) { $objWriter->startAttribute('w:hRule'); - $objWriter->text($heightRules); + $objWriter->text($heightRule); $objWriter->endAttribute(); } $objWriter->writeAttribute('w:val', $height); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 83d03e0c..18c67be3 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -9,7 +9,9 @@ echo date('H:i:s') , ' Create new PHPWord object' , EOL; $PHPWord = new PHPWord(); $section = $PHPWord->createSection(); -$section->addText("By default, a table row adds a textbreak after its content (notice the red border), even if the row height is <= height of the content"); +$section->addText("By default, when you insert an image, it adds a textbreak after its content."); +$section->addText("If we want a simple border around an image, we wrap the image inside a table->row->cell"); +$section->addText("On the image with the red border, even if we set the row height to the height of the image, the textbreak is still there:"); $table1 = $section->addTable(array("cellMargin"=> 0, "cellMarginRight"=> 0, "cellMarginBottom"=> 0, "cellMarginLeft"=> 0)); $table1->addRow(3750); @@ -17,16 +19,17 @@ $cell1 = $table1->addCell(null, array("valign" => "top", "borderSize" => 30, "bo $cell1->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); $section->addTextBreak(); -$section->addText("But if we set the row rule \"exact\", we get rid of the textbreak!"); +$section->addText("But if we set the rowStyle hRule \"exact\", the real row height is used, removing the textbreak:"); $table2 = $section->addTable(array("cellMargin"=> 0, "cellMarginRight"=> 0, "cellMarginBottom"=> 0, "cellMarginLeft"=> 0)); -$table2->addRow(3750, null, "exact"); +$table2->addRow(3750, array("heightRule"=>"exact")); $cell2 = $table2->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "00ff00")); $cell2->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); $section->addTextBreak(); $section->addText("In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips."); -$section->addText("So: $"."table2->addRow(3750, null, 'exact');"); +$section->addText("So: $"."table2->addRow(3750, array('heightRule'=>'exact'));"); +$section->addText("heightRule defaults to 'atLeast' when the row has an height set, and default to 'auto' otherwise"); // Save file $name = basename(__FILE__, '.php'); From 9faaa1b566b418577d56b4fe15cb461d4d234a35 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Fri, 28 Mar 2014 13:31:30 -0400 Subject: [PATCH 018/146] reverted table/row Signed-off-by: Julien Carignan --- Classes/PHPWord/Section/Table/Row.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/PHPWord/Section/Table/Row.php b/Classes/PHPWord/Section/Table/Row.php index 7ca99823..dd8ea65c 100644 --- a/Classes/PHPWord/Section/Table/Row.php +++ b/Classes/PHPWord/Section/Table/Row.php @@ -37,7 +37,7 @@ class PHPWord_Section_Table_Row * @var int */ private $_height = null; - + /** * Row style * From 772017d8e3ede9c308104d237ba5b7e41b57d2e1 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Fri, 28 Mar 2014 13:33:49 -0400 Subject: [PATCH 019/146] empty space remove --- Classes/PHPWord/Writer/Word2007/Base.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index 0a45fb20..16680ae2 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -569,7 +569,7 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart for ($i = 0; $i < $_cRows; $i++) { $row = $_rows[$i]; - $height = $row->getHeight(); + $height = $row->getHeight(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $cantSplit = $rowStyle->getCantSplit(); From 255af437f2ccbbb03e87f218a919c521cfdcc233 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 29 Mar 2014 00:57:23 +0700 Subject: [PATCH 020/146] Bugfix for footnote reference number and additional feature to insert text break and style the reference number --- CHANGELOG.md | 4 +- docs/elements.rst | 14 ++- samples/Sample_06_Footnote.php | 3 +- src/PhpWord/Section/Footnote.php | 14 +++ src/PhpWord/Writer/Word2007/Base.php | 53 ++------- src/PhpWord/Writer/Word2007/Document.php | 2 +- src/PhpWord/Writer/Word2007/Footnotes.php | 87 +++++++++++++-- src/PhpWord/Writer/Word2007/Styles.php | 105 ++++++++++-------- tests/PhpWord/Tests/Section/FootnoteTest.php | 49 ++++++++ .../Tests/Writer/Word2007/BaseTest.php | 13 ++- 10 files changed, 235 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 30be78e6..25689dbc 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 - Table: Add tblGrid element for Libre/Open Office table sizing - @gianis6 GH-183 +- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin +- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin ### Bugfixes -- +- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 ### Miscellaneous diff --git a/docs/elements.rst b/docs/elements.rst index d0f78d2e..f7ce0319 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -326,7 +326,8 @@ Footnotes --------- You can create footnotes in texts or textruns, but it's recommended to -use textrun to have better layout. +use textrun to have better layout. You can use ``addText``, ``addLink``, +and ``addTextBreak`` on a footnote. On textrun: @@ -335,7 +336,11 @@ On textrun: $textrun = $section->createTextRun(); $textrun->addText('Lead text.'); $footnote = $textrun->createFootnote(); - $footnote->addText('Footnote text.'); + $footnote->addText('Footnote text can have '); + $footnote->addLink('http://test.com', 'links'); + $footnote->addText('.'); + $footnote->addTextBreak(); + $footnote->addText('And text break.'); $textrun->addText('Trailing text.'); On text: @@ -345,3 +350,8 @@ On text: $section->addText('Lead text.'); $footnote = $section->createFootnote(); $footnote->addText('Footnote text.'); + +The footnote reference number will be displayed with decimal number starting +from 1. This number use ``FooterReference`` style which you can redefine by +``addFontStyle`` method. Default value for this style is +``array('superScript' => true)``; diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index c430e548..081d5918 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -24,7 +24,8 @@ $footnote->addText(' No break is placed after adding an element.', 'BoldText'); $footnote->addText(' All elements are placed inside a paragraph.', 'ColoredText'); $footnote->addText(' The best search engine: '); $footnote->addLink('http://www.google.com', null, 'NLink'); -$footnote->addText('. Also not bad: '); +$footnote->addText('. Also not bad:'); +$footnote->addTextBreak(); $footnote->addLink('http://www.bing.com', null, 'NLink'); $textrun->addText('The trailing text in the paragraph.'); diff --git a/src/PhpWord/Section/Footnote.php b/src/PhpWord/Section/Footnote.php index 857c4e20..c86d8e44 100644 --- a/src/PhpWord/Section/Footnote.php +++ b/src/PhpWord/Section/Footnote.php @@ -77,6 +77,20 @@ class Footnote return $text; } + /** + * Add TextBreak + * + * @param int $count + * @param mixed $fontStyle + * @param mixed $paragraphStyle + */ + public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) + { + for ($i = 1; $i <= $count; $i++) { + $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); + } + } + /** * Add a Link Element * diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 733b376a..7234aed9 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -125,7 +125,7 @@ class Base extends WriterPart } elseif ($element instanceof Image) { $this->_writeImage($xmlWriter, $element, true); } elseif ($element instanceof Footnote) { - $this->_writeFootnoteReference($xmlWriter, $element, true); + $this->_writeFootnote($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } @@ -1172,61 +1172,24 @@ class Base extends WriterPart } /** - * Write footnote element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote - */ - protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) - { - $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); - - $styleParagraph = $footnote->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $xmlWriter->startElement('w:p'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $elements = $footnote->getElements(); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); - } - } - } - - $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote - } - - /** - * Write footnote reference element + * Write footnote element which links to the actual content in footnotes.xml * * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section\Footnote $footnote * @param boolean $withoutP */ - protected function _writeFootnoteReference(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) + protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) { if (!$withoutP) { $xmlWriter->startElement('w:p'); } $xmlWriter->startElement('w:r'); - + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr $xmlWriter->startElement('w:footnoteReference'); $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); $xmlWriter->endElement(); // w:footnoteReference diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index ffce32d2..368d1b31 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -98,7 +98,7 @@ class Document extends Base } elseif ($element instanceof TOC) { $this->_writeTOC($xmlWriter); } elseif ($element instanceof Footnote) { - $this->_writeFootnoteReference($xmlWriter, $element); + $this->_writeFootnote($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 59d8cc1f..eb410393 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -10,6 +10,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Section\Footnote; +use PhpOffice\PhpWord\Section\Text; +use PhpOffice\PhpWord\Section\Link; +use PhpOffice\PhpWord\Section\TextBreak; +use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -27,19 +31,25 @@ class Footnotes extends Base // Create XML writer $xmlWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + $xmlWriter = new XMLWriter( + XMLWriter::STORAGE_DISK, + $this->getParentWriter()->getDiskCachingDirectory() + ); } else { $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } - // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('w:footnotes'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - - // write separator and continuation separator + $xmlWriter->writeAttribute( + 'xmlns:r', + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' + ); + $xmlWriter->writeAttribute( + 'xmlns:w', + 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' + ); + // Separator and continuation separator $xmlWriter->startElement('w:footnote'); $xmlWriter->writeAttribute('w:id', 0); $xmlWriter->writeAttribute('w:type', 'separator'); @@ -50,7 +60,7 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // w:footnote - + // Content $xmlWriter->startElement('w:footnote'); $xmlWriter->writeAttribute('w:id', 1); $xmlWriter->writeAttribute('w:type', 'continuationSeparator'); @@ -61,16 +71,69 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // w:footnote - foreach ($allFootnotesCollection as $footnote) { if ($footnote instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $footnote); + $this->writeFootnote($xmlWriter, $footnote); } } - $xmlWriter->endElement(); - // Return return $xmlWriter->getData(); } + + /** + * Write footnote content, overrides method in parent class + * + * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param PhpOffice\PhpWord\Section\Footnote $footnote + */ + private function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) + { + $xmlWriter->startElement('w:footnote'); + $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $xmlWriter->startElement('w:p'); + // Paragraph style + $paragraphStyle = $footnote->getParagraphStyle(); + $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; + if ($spIsObject) { + $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); + } elseif (!$spIsObject && !is_null($paragraphStyle)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:pStyle'); + $xmlWriter->writeAttribute('w:val', $paragraphStyle); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + // Reference symbol + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr + $xmlWriter->writeElement('w:footnoteRef'); + $xmlWriter->endElement(); // w:r + // Empty space after refence symbol + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw(' '); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + // Actual footnote contents + $elements = $footnote->getElements(); + if (count($elements) > 0) { + foreach ($elements as $element) { + if ($element instanceof Text) { + $this->_writeText($xmlWriter, $element, true); + } elseif ($element instanceof Link) { + $this->_writeLink($xmlWriter, $element, true); + } elseif ($element instanceof TextBreak) { + $xmlWriter->writeElement('w:br'); + } + } + } + $xmlWriter->endElement(); // w:p + $xmlWriter->endElement(); // w:footnote + } } diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index dc665300..a24ac516 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -21,11 +21,11 @@ use PhpOffice\PhpWord\Style\Paragraph; class Styles extends Base { /** - * PHPWord object + * PhpWord object * * @var PhpWord */ - private $_document; + private $phpWord; /** * Write word/styles.xml @@ -37,44 +37,28 @@ class Styles extends Base // Create XML writer $xmlWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + $xmlWriter = new XMLWriter( + XMLWriter::STORAGE_DISK, + $this->getParentWriter()->getDiskCachingDirectory() + ); } else { $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } - - $this->_document = $phpWord; - + $this->phpWord = $phpWord; // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('w:styles'); - - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - - // Write DocDefaults - $this->_writeDocDefaults($xmlWriter); - - // Write Style Definitions + $xmlWriter->writeAttribute( + 'xmlns:r', + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' + ); + $xmlWriter->writeAttribute( + 'xmlns:w', + 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' + ); + // Write default styles $styles = Style::getStyles(); - - // Write normal paragraph style - $normalStyle = null; - if (array_key_exists('Normal', $styles)) { - $normalStyle = $styles['Normal']; - } - $xmlWriter->startElement('w:style'); - $xmlWriter->writeAttribute('w:type', 'paragraph'); - $xmlWriter->writeAttribute('w:default', '1'); - $xmlWriter->writeAttribute('w:styleId', 'Normal'); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', 'Normal'); - $xmlWriter->endElement(); - if (!is_null($normalStyle)) { - $this->_writeParagraphStyle($xmlWriter, $normalStyle); - } - $xmlWriter->endElement(); - + $this->writeDefaultStyles($xmlWriter, $styles); // Write other styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { @@ -180,36 +164,65 @@ class Styles extends Base } /** - * Write document defaults + * Write default font and other default styles * * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param array $styles */ - private function _writeDocDefaults(XMLWriter $xmlWriter) + private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) { - $fontName = $this->_document->getDefaultFontName(); - $fontSize = $this->_document->getDefaultFontSize(); + $fontName = $this->phpWord->getDefaultFontName(); + $fontSize = $this->phpWord->getDefaultFontSize(); + // Default font $xmlWriter->startElement('w:docDefaults'); $xmlWriter->startElement('w:rPrDefault'); $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rFonts'); $xmlWriter->writeAttribute('w:ascii', $fontName); $xmlWriter->writeAttribute('w:hAnsi', $fontName); $xmlWriter->writeAttribute('w:eastAsia', $fontName); $xmlWriter->writeAttribute('w:cs', $fontName); - $xmlWriter->endElement(); - + $xmlWriter->endElement(); // w:rFonts $xmlWriter->startElement('w:sz'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); - $xmlWriter->endElement(); - + $xmlWriter->endElement(); // w:sz $xmlWriter->startElement('w:szCs'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:szCs + $xmlWriter->endElement(); // w:rPr + $xmlWriter->endElement(); // w:rPrDefault + $xmlWriter->endElement(); // w:docDefaults - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + // Normal style + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'paragraph'); + $xmlWriter->writeAttribute('w:default', '1'); + $xmlWriter->writeAttribute('w:styleId', 'Normal'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', 'Normal'); + $xmlWriter->endElement(); // w:name + if (array_key_exists('Normal', $styles)) { + $this->_writeParagraphStyle($xmlWriter, $styles['Normal']); + } + $xmlWriter->endElement(); // w:style + + // FootnoteReference style + if (!array_key_exists('FootnoteReference', $styles)) { + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'character'); + $xmlWriter->writeAttribute('w:styleId', 'FootnoteReference'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', 'Footnote Reference'); + $xmlWriter->endElement(); // w:name + $xmlWriter->writeElement('w:semiHidden'); + $xmlWriter->writeElement('w:unhideWhenUsed'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:vertAlign'); + $xmlWriter->writeAttribute('w:val', 'superscript'); + $xmlWriter->endElement(); // w:vertAlign + $xmlWriter->endElement(); // w:rPr + $xmlWriter->endElement(); // w:style + } } } diff --git a/tests/PhpWord/Tests/Section/FootnoteTest.php b/tests/PhpWord/Tests/Section/FootnoteTest.php index 19cf58c7..ed2e36de 100644 --- a/tests/PhpWord/Tests/Section/FootnoteTest.php +++ b/tests/PhpWord/Tests/Section/FootnoteTest.php @@ -19,6 +19,11 @@ use PhpOffice\PhpWord\Section\Footnote; */ class FootnoteTest extends \PHPUnit_Framework_TestCase { + /** + * New instance without parameter + * + * @covers ::__construct + */ public function testConstruct() { $oFootnote = new Footnote(); @@ -28,6 +33,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oFootnote->getParagraphStyle(), null); } + /** + * New instance with string parameter + * + * @covers ::__construct + */ public function testConstructString() { $oFootnote = new Footnote('pStyle'); @@ -35,6 +45,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oFootnote->getParagraphStyle(), 'pStyle'); } + /** + * New instance with array parameter + * + * @covers ::__construct + */ public function testConstructArray() { $oFootnote = new Footnote(array('spacing' => 100)); @@ -45,6 +60,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase ); } + /** + * Add text element + * + * @covers ::addText + */ public function testAddText() { $oFootnote = new Footnote(); @@ -54,6 +74,24 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); } + /** + * Add text break element + * + * @covers ::addTextBreak + */ + public function testAddTextBreak() + { + $oFootnote = new Footnote(); + $oFootnote->addTextBreak(2); + + $this->assertCount(2, $oFootnote->getElements()); + } + + /** + * Add link element + * + * @covers ::addLink + */ public function testAddLink() { $oFootnote = new Footnote(); @@ -63,6 +101,12 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); } + /** + * Set/get reference Id + * + * @covers ::setReferenceId + * @covers ::getReferenceId + */ public function testReferenceId() { $oFootnote = new Footnote(); @@ -72,6 +116,11 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oFootnote->getReferenceId(), $iVal); } + /** + * Get elements + * + * @covers ::getElements + */ public function testGetElements() { $oFootnote = new Footnote(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php index ac14fd17..e4abb7a1 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php @@ -79,9 +79,13 @@ class BaseTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->createSection(); + $fontStyleArray = array('bold' => true); + $fontStyleName = 'Test'; $expected = 'PhpWord'; $section->addLink('http://github.com/phpoffice/phpword', $expected); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t'); @@ -97,8 +101,14 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $section = $phpWord->createSection(); $footer = $section->createFooter(); + $fontStyleArray = array('bold' => true); + $fontStyleName = 'Font'; + $paragraphStyleArray = array('align' => 'right'); + $paragraphStyleName = 'Paragraph'; - $footer->addPreserveText('{PAGE}'); + $footer->addPreserveText('Page {PAGE}'); + $footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray); + $footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $preserve = $doc->getElement("w:p/w:r[2]/w:instrText", 'word/footer1.xml'); @@ -193,6 +203,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $styles['superScript'] = true; $styles['color'] = 'FF0000'; $styles['fgColor'] = 'yellow'; + $styles['hint'] = 'eastAsia'; $section = $phpWord->createSection(); $section->addText('Test', $styles); From 612ad857739ff7cdb6e26fbfa8585588e33a0596 Mon Sep 17 00:00:00 2001 From: Julien Carignan Date: Fri, 28 Mar 2014 15:21:01 -0400 Subject: [PATCH 021/146] changed heightRule string to exactHeight bool --- Classes/PHPWord/Style/Row.php | 26 ++++++++++++------------ Classes/PHPWord/Writer/Word2007/Base.php | 6 +++--- samples/Sample_21_TableRowRules.php | 7 +++---- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Classes/PHPWord/Style/Row.php b/Classes/PHPWord/Style/Row.php index aae7e851..d779d3cc 100644 --- a/Classes/PHPWord/Style/Row.php +++ b/Classes/PHPWord/Style/Row.php @@ -46,11 +46,11 @@ class PHPWord_Style_Row private $_cantSplit = false; /** - * Table row height rule (auto, exact, atLeast) + * Table row exact height * - * @var String + * @var bool */ - private $_heightRule = null; + private $_exactHeight = false; /** * Create a new row style @@ -121,27 +121,27 @@ class PHPWord_Style_Row } /** - * Set heightRule + * Set exactHeight * - * @param String $pValue + * @param bool $pValue * @return PHPWord_Style_Row */ - public function setHeightRule($pValue = false) + public function setExactHeight($pValue = false) { - if (!is_string($pValue)) { - $pValue = null; + if (!is_bool($pValue)) { + $pValue = false; } - $this->_heightRule = $pValue; + $this->_exactHeight = $pValue; return $this; } /** - * Get heightRule + * Get exactHeight * - * @return heightRule + * @return boolean */ - public function getHeightRule() + public function getExactHeight() { - return $this->_heightRule; + return $this->_exactHeight; } } diff --git a/Classes/PHPWord/Writer/Word2007/Base.php b/Classes/PHPWord/Writer/Word2007/Base.php index 16680ae2..1cf3bad3 100755 --- a/Classes/PHPWord/Writer/Word2007/Base.php +++ b/Classes/PHPWord/Writer/Word2007/Base.php @@ -573,7 +573,7 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $cantSplit = $rowStyle->getCantSplit(); - $heightRule = $rowStyle->getHeightRule(); + $exactHeight = $rowStyle->getExactHeight(); $objWriter->startElement('w:tr'); @@ -581,9 +581,9 @@ class PHPWord_Writer_Word2007_Base extends PHPWord_Writer_Word2007_WriterPart $objWriter->startElement('w:trPr'); if (!is_null($height)) { $objWriter->startElement('w:trHeight'); - if(!is_null($heightRule)) { + if($exactHeight) { $objWriter->startAttribute('w:hRule'); - $objWriter->text($heightRule); + $objWriter->text("exact"); $objWriter->endAttribute(); } $objWriter->writeAttribute('w:val', $height); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 18c67be3..1082f99f 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -19,17 +19,16 @@ $cell1 = $table1->addCell(null, array("valign" => "top", "borderSize" => 30, "bo $cell1->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); $section->addTextBreak(); -$section->addText("But if we set the rowStyle hRule \"exact\", the real row height is used, removing the textbreak:"); +$section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); $table2 = $section->addTable(array("cellMargin"=> 0, "cellMarginRight"=> 0, "cellMarginBottom"=> 0, "cellMarginLeft"=> 0)); -$table2->addRow(3750, array("heightRule"=>"exact")); +$table2->addRow(3750, array("exactHeight"=>)); $cell2 = $table2->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "00ff00")); $cell2->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); $section->addTextBreak(); $section->addText("In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips."); -$section->addText("So: $"."table2->addRow(3750, array('heightRule'=>'exact'));"); -$section->addText("heightRule defaults to 'atLeast' when the row has an height set, and default to 'auto' otherwise"); +$section->addText("So: $"."table2->addRow(3750, array('exactHeight'=>true));"); // Save file $name = basename(__FILE__, '.php'); From c91d6b61c9af18f182070b59b24a9a7a31532afd Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 29 Mar 2014 22:26:00 +0700 Subject: [PATCH 022/146] Writer unit test enhancements --- src/PhpWord/Writer/RTF.php | 2 +- tests/PhpWord/Tests/Writer/ODTextTest.php | 28 +++---- tests/PhpWord/Tests/Writer/RTFTest.php | 67 ++++++++-------- .../Tests/Writer/Word2007/BaseTest.php | 18 ++++- .../Tests/Writer/Word2007/DocumentTest.php | 10 +-- tests/PhpWord/Tests/Writer/Word2007Test.php | 76 ++++++++++++++++--- 6 files changed, 134 insertions(+), 67 deletions(-) diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index b9aa3aa3..970d91ad 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -438,7 +438,7 @@ class RTF implements IWriter if ($styleFont->getBold()) { $sRTFText .= '\b'; } - if ($styleFont->getBold()) { + if ($styleFont->getItalic()) { $sRTFText .= '\i'; } if ($styleFont->getSize()) { diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index f65ce79f..8c345f55 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -14,13 +14,12 @@ use PhpOffice\PhpWord\Writer\ODText; /** * Test class for PhpOffice\PhpWord\Writer\ODText * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText * @runTestsInSeparateProcesses */ class ODTextTest extends \PHPUnit_Framework_TestCase { /** - * Test construct + * Construct */ public function testConstruct() { @@ -43,9 +42,10 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getPhpWord - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception - * @expectedExceptionMessage No PhpWord assigned. + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() { @@ -54,7 +54,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save + * Save */ public function testSave() { @@ -89,7 +89,8 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save + * Save php output + * * @todo Haven't got any method to test this */ public function testSavePhpOutput() @@ -102,8 +103,9 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception * @expectedExceptionMessage PhpWord object unassigned. */ public function testSaveException() @@ -113,7 +115,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getWriterPart + * Get writer part return null value */ public function testGetWriterPartNull() { @@ -122,8 +124,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setUseDiskCaching - * @covers ::getUseDiskCaching + * Set/get use disk caching */ public function testSetGetUseDiskCaching() { @@ -134,7 +135,8 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setUseDiskCaching + * Use disk caching exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ public function testSetUseDiskCachingException() diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 9707c05f..7b546438 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -14,13 +14,12 @@ use PhpOffice\PhpWord\Writer\RTF; /** * Test class for PhpOffice\PhpWord\Writer\RTF * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\RTF * @runTestsInSeparateProcesses */ class RTFTest extends \PHPUnit_Framework_TestCase { /** - * covers ::construct + * Construct */ public function testConstruct() { @@ -31,8 +30,9 @@ class RTFTest extends \PHPUnit_Framework_TestCase } /** - * covers ::__construct - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() @@ -42,32 +42,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save - * @todo Haven't got any method to test this - */ - public function testSavePhpOutput() - { - $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $section->addText('Test'); - $writer = new RTF($phpWord); - $writer->save('php://output'); - } - - /** - * @covers ::save - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception - * @expectedExceptionMessage PhpWord object unassigned. - */ - public function testSaveException() - { - $writer = new RTF(); - $writer->save(); - } - - /** - * @covers ::save - * @covers :: + * Save */ public function testSave() { @@ -76,12 +51,12 @@ class RTFTest extends \PHPUnit_Framework_TestCase $file = __DIR__ . "/../_files/temp.rtf"; $phpWord = new PhpWord(); - $phpWord->addFontStyle('Font', array('size' => 11)); + $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); $section = $phpWord->createSection(); - $section->addText('Test 1', 'Font'); + $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); - $section->addText('Test 2', null, 'Paragraph'); + $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); @@ -101,4 +76,30 @@ class RTFTest extends \PHPUnit_Framework_TestCase unlink($file); } + + /** + * Save + * + * @todo Haven't got any method to test this + */ + public function testSavePhpOutput() + { + $phpWord = new PhpWord(); + $section = $phpWord->createSection(); + $section->addText('Test'); + $writer = new RTF($phpWord); + $writer->save('php://output'); + } + + /** + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedExceptionMessage PhpWord object unassigned. + */ + public function testSaveException() + { + $writer = new RTF(); + $writer->save(); + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php index e4abb7a1..68baeb2b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php @@ -65,7 +65,8 @@ class BaseTest extends \PHPUnit_Framework_TestCase $textrun->addTextBreak(); $textrun = $section->createTextRun($aStyle); $textrun->addLink('http://test.com'); - $textrun->addImage($imageSrc); + $textrun->addImage($imageSrc, array('align' => 'top')); + $textrun->createFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); $parent = "/w:document/w:body/w:p"; @@ -80,12 +81,14 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $section = $phpWord->createSection(); $fontStyleArray = array('bold' => true); - $fontStyleName = 'Test'; + $fontStyleName = 'Font Style'; + $paragraphStyleArray = array('align' => 'center'); + $paragraphStyleName = 'Paragraph Style'; $expected = 'PhpWord'; $section->addLink('http://github.com/phpoffice/phpword', $expected); - $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray); - $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray, $paragraphStyleArray); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t'); @@ -230,6 +233,10 @@ class BaseTest extends \PHPUnit_Framework_TestCase $tWidth = 120; $rHeight = 120; $cWidth = 120; + $imageSrc = __DIR__ . "/../../_files/images/earth.jpg"; + $objectSrc = __DIR__ . "/../../_files/documents/sheet.xls"; + + $tStyles["width"] = 50; $tStyles["cellMarginTop"] = 120; $tStyles["cellMarginRight"] = 120; $tStyles["cellMarginBottom"] = 120; @@ -247,6 +254,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cStyles["borderBottomColor"] = 'FF0000'; $cStyles["borderLeftColor"] = 'FF0000'; $cStyles["borderRightColor"] = 'FF0000'; + $cStyles["vMerge"] = 'restart'; $section = $phpWord->createSection(); $table = $section->addTable($tStyles); @@ -257,6 +265,8 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cell->addTextBreak(); $cell->addLink('http://google.com'); $cell->addListItem('Test'); + $cell->addImage($imageSrc); + $cell->addObject($objectSrc); $textrun = $cell->createTextRun(); $textrun->addText('Test'); diff --git a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php index 6c3335d3..f0b44e0b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php @@ -14,7 +14,6 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Document * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Document * @runTestsInSeparateProcesses */ class DocumentTest extends \PHPUnit_Framework_TestCase @@ -27,6 +26,9 @@ class DocumentTest extends \PHPUnit_Framework_TestCase TestHelperDOCX::clear(); } + /** + * Write end section page numbering + */ public function testWriteEndSectionPageNumbering() { $phpWord = new PhpWord(); @@ -40,11 +42,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeTOC - * covers ::_writePageBreak - * covers ::_writeListItem - * covers ::_writeTitle - * covers ::_writeObject + * Write elements */ public function testElements() { diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index 5fcf37e2..22a1c0df 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -15,18 +15,20 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007 * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007 * @runTestsInSeparateProcesses */ class Word2007Test extends \PHPUnit_Framework_TestCase { + /** + * Tear down after each test + */ public function tearDown() { TestHelperDOCX::clear(); } /** - * covers ::__construct + * Construct */ public function testConstruct() { @@ -57,10 +59,12 @@ class Word2007Test extends \PHPUnit_Framework_TestCase } /** - * @covers ::save + * Save */ public function testSave() { + $localImage = __DIR__ . '/../_files/images/earth.jpg'; + $remoteImage = 'http://php.net//images/logos/php-med-trans-light.gif'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); @@ -71,16 +75,55 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $section = $phpWord->createSection(); $textrun = $section->createTextRun(); $textrun->addText('Test 3'); + $footnote = $textrun->createFootnote(); + $footnote->addLink('http://test.com'); + $header = $section->createHeader(); + $header->addImage($localImage); + $footer = $section->createFooter(); + $footer->addImage($remoteImage); $writer = new Word2007($phpWord); $file = __DIR__ . "/../_files/temp.docx"; $writer->save($file); - $this->assertTrue(\file_exists($file)); + + $this->assertTrue(file_exists($file)); + unlink($file); } /** - * @covers ::checkContentTypes + * Save using disk caching + */ + public function testSaveUseDiskCaching() + { + $phpWord = new PhpWord(); + $section = $phpWord->createSection(); + $section->addText('Test'); + + $writer = new Word2007($phpWord); + $writer->setUseDiskCaching(true); + $file = __DIR__ . "/../_files/temp.docx"; + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } + + /** + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedExceptionMessage PhpWord object unassigned. + */ + public function testSaveException() + { + $writer = new Word2007(); + $writer->save(); + } + + /** + * Check content types */ public function testCheckContentTypes() { @@ -110,20 +153,33 @@ class Word2007Test extends \PHPUnit_Framework_TestCase } /** - * @covers ::setUseDiskCaching - * @covers ::getUseDiskCaching + * Get writer part return null value + */ + public function testGetWriterPartNull() + { + $object = new Word2007(); + $this->assertNull($object->getWriterPart()); + } + + /** + * Set/get use disk caching */ public function testSetGetUseDiskCaching() { - $object = new Word2007(); + $phpWord = new PhpWord(); + $section = $phpWord->createSection(); + $object = new Word2007($phpWord); $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); + $writer = new Word2007($phpWord); + $writer->save('php://output'); $this->assertTrue($object->getUseDiskCaching()); } /** - * @covers ::setUseDiskCaching - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Use disk caching exception + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ public function testSetUseDiskCachingException() { From 970cb32b4566c08b0ed5b57ae200fb9299f1f0d9 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 01:17:22 +0700 Subject: [PATCH 023/146] Fix deprecated method, unused parts, initial definition, and @method annotation --- samples/Sample_13_Images.php | 2 +- src/PhpWord/DocumentProperties.php | 9 --------- src/PhpWord/Media.php | 1 + src/PhpWord/Shared/XMLWriter.php | 1 + 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 6841ed64..cf467464 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -17,7 +17,7 @@ $section->addTextBreak(2); $source = 'http://php.net/images/logos/php-med-trans-light.gif'; $section->addText("Remote image from: {$source}"); -$section->addMemoryImage($source); +$section->addImage($source); // End code // Save file diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index cc24e35a..5e982646 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -476,41 +476,33 @@ class DocumentProperties switch ($propertyType) { case 'empty': // Empty return ''; - break; case 'null': // Null return null; - break; case 'i1': // 1-Byte Signed Integer case 'i2': // 2-Byte Signed Integer case 'i4': // 4-Byte Signed Integer case 'i8': // 8-Byte Signed Integer case 'int': // Integer return (int) $propertyValue; - break; case 'ui1': // 1-Byte Unsigned Integer case 'ui2': // 2-Byte Unsigned Integer case 'ui4': // 4-Byte Unsigned Integer case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return abs((int) $propertyValue); - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return (float) $propertyValue; - break; case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return $propertyValue; - break; case 'date': // Date and Time case 'filetime': // File Time return strtotime($propertyValue); - break; case 'bool': // Boolean return ($propertyValue == 'true') ? true : false; - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -525,7 +517,6 @@ class DocumentProperties case 'clsid': // Class ID case 'cf': // Clipboard Data return $propertyValue; - break; } return $propertyValue; diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 80cde281..a9a9a6af 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -242,6 +242,7 @@ class Media $cImg = self::countFooterMediaElements($key); $rID = $cImg + 1; $cImg++; + $media = array(); $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 5b21e7b1..e27013d5 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -20,6 +20,7 @@ if (!defined('DATE_W3C')) { /** * XMLWriter wrapper * + * @method bool writeElement(string $name, string $content = null) * @method bool startElement(string $name) * @method bool writeAttribute(string $name, string $value) * @method bool endElement() From 05a4b952557f4d6fedda95362474f8a8d8c95715 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 11:09:14 +0700 Subject: [PATCH 024/146] Unit test enhancements --- src/PhpWord/Section/CheckBox.php | 17 --- src/PhpWord/Writer/Word2007/Base.php | 12 -- tests/PhpWord/Tests/Section/CheckBoxTest.php | 11 ++ tests/PhpWord/Tests/Section/FooterTest.php | 62 ++++++++-- tests/PhpWord/Tests/Section/FootnoteTest.php | 18 --- tests/PhpWord/Tests/Section/HeaderTest.php | 59 ++++++++- tests/PhpWord/Tests/Section/ImageTest.php | 50 +++++++- .../PhpWord/Tests/Section/Table/CellTest.php | 115 ++++++++++++++++-- tests/PhpWord/Tests/Section/TextRunTest.php | 39 +++++- tests/PhpWord/Tests/Section/TextTest.php | 24 +++- tests/PhpWord/Tests/SectionTest.php | 2 +- .../Tests/Writer/Word2007/DocumentTest.php | 42 ++++++- .../Tests/Writer/Word2007/FootnotesTest.php | 10 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 2 + 14 files changed, 378 insertions(+), 85 deletions(-) diff --git a/src/PhpWord/Section/CheckBox.php b/src/PhpWord/Section/CheckBox.php index f39ad841..57671b84 100644 --- a/src/PhpWord/Section/CheckBox.php +++ b/src/PhpWord/Section/CheckBox.php @@ -45,13 +45,6 @@ class CheckBox */ private $paragraphStyle; - /** - * Cell Element Collection - * - * @var array - */ - private $_elementCollection = array(); - /** * Create a new Text Element * @@ -174,14 +167,4 @@ class CheckBox { return $this->text; } - - /** - * Get all Elements - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 5703a5a9..c32eede3 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1223,11 +1223,6 @@ class Base extends WriterPart */ protected function _writeCheckBox(XMLWriter $xmlWriter, CheckBox $checkbox, $withoutP = false, $checkState = false) { - $count = 1; - $_elements = $checkbox->getElements(); - if (count($_elements) > 1) { - $count = $count + 1; - } $name = htmlspecialchars($checkbox->getName()); $name = String::controlCharacterPHP2OOXML($name); $text = htmlspecialchars($checkbox->getText()); @@ -1271,9 +1266,6 @@ class Base extends WriterPart $xmlWriter->endElement(); // w:fldChar $xmlWriter->endElement(); // w:r - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:name', $name); - $xmlWriter->writeAttribute('w:id', $count); $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:instrText'); $xmlWriter->writeAttribute('xml:space', 'preserve'); @@ -1290,10 +1282,6 @@ class Base extends WriterPart $xmlWriter->writeAttribute('w:fldCharType', 'end'); $xmlWriter->endElement();// w:fldChar $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:bookmarkStart - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $count); - $xmlWriter->endElement();// w:bookmarkEnd $xmlWriter->startElement('w:r'); if ($sfIsObject) { diff --git a/tests/PhpWord/Tests/Section/CheckBoxTest.php b/tests/PhpWord/Tests/Section/CheckBoxTest.php index b69217a5..d07a0b69 100644 --- a/tests/PhpWord/Tests/Section/CheckBoxTest.php +++ b/tests/PhpWord/Tests/Section/CheckBoxTest.php @@ -10,6 +10,7 @@ namespace PhpOffice\PhpWord\Tests\Section; use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Style\Font; /** * Test class for PhpOffice\PhpWord\Section\CheckBox @@ -54,6 +55,16 @@ class CheckBoxTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); } + /** + * Font style as object + */ + public function testFontObject() + { + $font = new Font(); + $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font); + $this->assertEquals($oCheckBox->getFontStyle(), $font); + } + /** * Get paragraph style */ diff --git a/tests/PhpWord/Tests/Section/FooterTest.php b/tests/PhpWord/Tests/Section/FooterTest.php index 6ae3bc60..d14f125c 100644 --- a/tests/PhpWord/Tests/Section/FooterTest.php +++ b/tests/PhpWord/Tests/Section/FooterTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\Footer; /** * Test class for PhpOffice\PhpWord\Section\Footer * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Footer * @runTestsInSeparateProcesses */ class FooterTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstruct() { $iVal = rand(1, 1000); @@ -28,15 +30,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oFooter->getFooterCount(), $iVal); } - public function testRelationID() - { - $oFooter = new Footer(0); - - $iVal = rand(1, 1000); - $oFooter->setRelationId($iVal); - $this->assertEquals($oFooter->getRelationId(), $iVal); - } - + /** + * Add text + */ public function testAddText() { $oFooter = new Footer(1); @@ -46,6 +42,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oFooter = new Footer(1); @@ -56,6 +55,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add text break + */ public function testAddTextBreak() { $oFooter = new Footer(1); @@ -65,6 +67,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertCount($iVal, $oFooter->getElements()); } + /** + * Add text run + */ public function testCreateTextRun() { $oFooter = new Footer(1); @@ -74,6 +79,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); } + /** + * Add table + */ public function testAddTable() { $oFooter = new Footer(1); @@ -83,16 +91,23 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $element); } + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; $oFooter = new Footer(1); - $element = $oFooter->addImage($src); + $element1 = $oFooter->addImage($src); + $element2 = $oFooter->addMemoryImage($src); // @deprecated - $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertCount(2, $oFooter->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); } + /** + * Add image by URL + */ public function testAddImageByUrl() { $oFooter = new Footer(1); @@ -104,6 +119,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } + /** + * Add preserve text + */ public function testAddPreserveText() { $oFooter = new Footer(1); @@ -113,6 +131,9 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oFooter = new Footer(1); @@ -123,10 +144,25 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), array('ééé')); } + /** + * Get elements + */ public function testGetElements() { $oFooter = new Footer(1); $this->assertInternalType('array', $oFooter->getElements()); } + + /** + * Set/get relation Id + */ + public function testRelationID() + { + $oFooter = new Footer(0); + + $iVal = rand(1, 1000); + $oFooter->setRelationId($iVal); + $this->assertEquals($oFooter->getRelationId(), $iVal); + } } diff --git a/tests/PhpWord/Tests/Section/FootnoteTest.php b/tests/PhpWord/Tests/Section/FootnoteTest.php index ed2e36de..fc537ab8 100644 --- a/tests/PhpWord/Tests/Section/FootnoteTest.php +++ b/tests/PhpWord/Tests/Section/FootnoteTest.php @@ -14,15 +14,12 @@ use PhpOffice\PhpWord\Section\Footnote; /** * Test class for PhpOffice\PhpWord\Section\Footnote * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Footnote * @runTestsInSeparateProcesses */ class FootnoteTest extends \PHPUnit_Framework_TestCase { /** * New instance without parameter - * - * @covers ::__construct */ public function testConstruct() { @@ -35,8 +32,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * New instance with string parameter - * - * @covers ::__construct */ public function testConstructString() { @@ -47,8 +42,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * New instance with array parameter - * - * @covers ::__construct */ public function testConstructArray() { @@ -62,8 +55,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * Add text element - * - * @covers ::addText */ public function testAddText() { @@ -76,8 +67,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * Add text break element - * - * @covers ::addTextBreak */ public function testAddTextBreak() { @@ -89,8 +78,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * Add link element - * - * @covers ::addLink */ public function testAddLink() { @@ -103,9 +90,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * Set/get reference Id - * - * @covers ::setReferenceId - * @covers ::getReferenceId */ public function testReferenceId() { @@ -118,8 +102,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase /** * Get elements - * - * @covers ::getElements */ public function testGetElements() { diff --git a/tests/PhpWord/Tests/Section/HeaderTest.php b/tests/PhpWord/Tests/Section/HeaderTest.php index 795b49c3..edc5d2c6 100644 --- a/tests/PhpWord/Tests/Section/HeaderTest.php +++ b/tests/PhpWord/Tests/Section/HeaderTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\Header; /** * Test class for PhpOffice\PhpWord\Section\Header * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Header * @runTestsInSeparateProcesses */ class HeaderTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstructDefault() { $iVal = rand(1, 1000); @@ -29,6 +31,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::AUTO); } + /** + * Add text + */ public function testAddText() { $oHeader = new Header(1); @@ -39,6 +44,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'text'); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oHeader = new Header(1); @@ -49,6 +57,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add text break + */ public function testAddTextBreak() { $oHeader = new Header(1); @@ -56,6 +67,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oHeader->getElements()); } + /** + * Add text break with params + */ public function testAddTextBreakWithParams() { $oHeader = new Header(1); @@ -64,6 +78,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount($iVal, $oHeader->getElements()); } + /** + * Add text run + */ public function testCreateTextRun() { $oHeader = new Header(1); @@ -72,6 +89,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oHeader->getElements()); } + /** + * Add table + */ public function testAddTable() { $oHeader = new Header(1); @@ -80,16 +100,23 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oHeader->getElements()); } + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; $oHeader = new Header(1); - $element = $oHeader->addImage($src); + $element1 = $oHeader->addImage($src); + $element2 = $oHeader->addMemoryImage($src); // @deprecated - $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertCount(2, $oHeader->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); } + /** + * Add image by URL + */ public function testAddImageByUrl() { $oHeader = new Header(1); @@ -101,6 +128,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } + /** + * Add preserve text + */ public function testAddPreserveText() { $oHeader = new Header(1); @@ -110,6 +140,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oHeader = new Header(1); @@ -120,6 +153,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), array('ééé')); } + /** + * Add watermark + */ public function testAddWatermark() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -130,6 +166,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } + /** + * Get elements + */ public function testGetElements() { $oHeader = new Header(1); @@ -137,6 +176,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertInternalType('array', $oHeader->getElements()); } + /** + * Set/get relation Id + */ public function testRelationId() { $oHeader = new Header(1); @@ -146,6 +188,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getRelationId(), $iVal); } + /** + * Reset type + */ public function testResetType() { $oHeader = new Header(1); @@ -155,6 +200,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::AUTO); } + /** + * First page + */ public function testFirstPage() { $oHeader = new Header(1); @@ -163,6 +211,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::FIRST); } + /** + * Even page + */ public function testEvenPage() { $oHeader = new Header(1); diff --git a/tests/PhpWord/Tests/Section/ImageTest.php b/tests/PhpWord/Tests/Section/ImageTest.php index 7e4a25b4..bd4bf394 100644 --- a/tests/PhpWord/Tests/Section/ImageTest.php +++ b/tests/PhpWord/Tests/Section/ImageTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\Image; /** * Test class for PhpOffice\PhpWord\Section\Image * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Image * @runTestsInSeparateProcesses */ class ImageTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstruct() { $src = __DIR__ . "/../_files/images/firefox.png"; @@ -31,6 +33,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } + /** + * New instance with style + */ public function testConstructWithStyle() { $src = __DIR__ . "/../_files/images/firefox.png"; @@ -44,7 +49,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::__construct + * Valid image types */ public function testValidImageTypes() { @@ -57,8 +62,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase } /** + * Image not found + * * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidImageException - * @covers ::__construct */ public function testImageNotFound() { @@ -66,14 +72,18 @@ class ImageTest extends \PHPUnit_Framework_TestCase } /** + * Invalid image types + * * @expectedException \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException - * @covers ::__construct */ public function testInvalidImageTypes() { new Image(__DIR__ . "/../_files/images/alexz-johnson.pcx"); } + /** + * Get style + */ public function testStyle() { $oImage = new Image( @@ -84,6 +94,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } + /** + * Get relation Id + */ public function testRelationID() { $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); @@ -92,12 +105,19 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getRelationId(), $iVal); } + /** + * Get is watermark + */ public function testWatermark() { $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); $oImage->setIsWatermark(true); $this->assertEquals($oImage->getIsWatermark(), true); } + + /** + * Test PNG + */ public function testPNG() { $src = __DIR__ . "/../_files/images/firefox.png"; @@ -112,6 +132,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getImageType(), 'image/png'); } + /** + * Test GIF + */ public function testGIF() { $src = __DIR__ . "/../_files/images/mario.gif"; @@ -126,6 +149,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getImageType(), 'image/gif'); } + /** + * Test JPG + */ public function testJPG() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -140,6 +166,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getImageType(), 'image/jpeg'); } + /** + * Test BMP + */ public function testBMP() { $oImage = new Image(__DIR__ . "/../_files/images/duke_nukem.bmp"); @@ -150,4 +179,17 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getImageExtension(), 'bmp'); $this->assertEquals($oImage->getImageType(), 'image/bmp'); } + + /** + * Test TIFF + */ + public function testTIFF() + { + $oImage = new Image(__DIR__ . "/../_files/images/angela_merkel.tif"); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertEquals($oImage->getImageCreateFunction(), null); + $this->assertEquals($oImage->getImageFunction(), null); + $this->assertEquals($oImage->getImageType(), 'image/tiff'); + } } diff --git a/tests/PhpWord/Tests/Section/Table/CellTest.php b/tests/PhpWord/Tests/Section/Table/CellTest.php index fc0c0a97..6f38d986 100644 --- a/tests/PhpWord/Tests/Section/Table/CellTest.php +++ b/tests/PhpWord/Tests/Section/Table/CellTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\Table\Cell; /** * Test class for PhpOffice\PhpWord\Section\Table\Cell * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Table\Cell * @runTestsInSeparateProcesses */ class CellTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstruct() { $iVal = rand(1, 1000); @@ -28,6 +30,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oCell->getWidth(), null); } + /** + * New instance with array + */ public function testConstructWithStyleArray() { $iVal = rand(1, 1000); @@ -37,6 +42,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oCell->getWidth(), null); } + /** + * New instance with string + */ public function testConstructWithStyleString() { $iVal = rand(1, 1000); @@ -45,6 +53,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oCell->getStyle(), 'cellStyle'); } + /** + * Add text + */ public function testAddText() { $oCell = new Cell('section', 1); @@ -54,6 +65,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); } + /** + * Add non-UTF8 + */ public function testAddTextNotUTF8() { $oCell = new Cell('section', 1); @@ -64,15 +78,31 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add link + */ public function testAddLink() { $oCell = new Cell('section', 1); - $element = $oCell->addLink('http://www.google.fr', 'Nom'); + $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); } + /** + * Add link exception + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + */ + public function testAddLinkException() + { + $oCell = new Cell('header', 1); + $element = $oCell->addLink('http://google.com', 'Google'); + } + + /** + * Add text break + */ public function testAddTextBreak() { $oCell = new Cell('section', 1); @@ -81,6 +111,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oCell->getElements()); } + /** + * Add list item + */ public function testAddListItem() { $oCell = new Cell('section', 1); @@ -91,6 +124,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getTextObject()->getText(), 'text'); } + /** + * Add list item non-UTF8 + */ public function testAddListItemNotUTF8() { $oCell = new Cell('section', 1); @@ -101,16 +137,23 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getTextObject()->getText(), 'ééé'); } + /** + * Add image section + */ public function testAddImageSection() { $src = __DIR__ . "/../../_files/images/earth.jpg"; $oCell = new Cell('section', 1); - $element = $oCell->addImage($src); + $element1 = $oCell->addImage($src); + $element2 = $oCell->addMemoryImage($src); // @deprecated - $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertCount(2, $oCell->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); } + /** + * Add image header + */ public function testAddImageHeader() { $src = __DIR__ . "/../../_files/images/earth.jpg"; @@ -121,6 +164,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } + /** + * Add image footer + */ public function testAddImageFooter() { $src = __DIR__ . "/../../_files/images/earth.jpg"; @@ -131,7 +177,10 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } - public function testAddSectionImageByUrl() + /** + * Add image section by URL + */ + public function testAddImageSectionByUrl() { $oCell = new Cell('section', 1); $element = $oCell->addImage( @@ -142,7 +191,10 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } - public function testAddHeaderImageByUrl() + /** + * Add image header by URL + */ + public function testAddImageHeaderByUrl() { $oCell = new Cell('header', 1); $element = $oCell->addImage( @@ -153,7 +205,10 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } - public function testAddFooterImageByUrl() + /** + * Add image footer by URL + */ + public function testAddImageFooterByUrl() { $oCell = new Cell('footer', 1); $element = $oCell->addImage( @@ -164,6 +219,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); } + /** + * Add object + */ public function testAddObjectXLS() { $src = __DIR__ . "/../../_files/documents/sheet.xls"; @@ -174,6 +232,21 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $element); } + /** + * Test add object exception + * + * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidObjectException + */ + public function testAddObjectException() + { + $src = __DIR__ . "/_files/xsl/passthrough.xsl"; + $oCell = new Cell('section', 1); + $element = $oCell->addObject($src); + } + + /** + * Add preserve text + */ public function testAddPreserveText() { $oCell = new Cell('header', 1); @@ -183,6 +256,9 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oCell = new Cell('header', 1); @@ -193,6 +269,20 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), array('ééé')); } + /** + * Add preserve text exception + * + * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + */ + public function testAddPreserveTextException() + { + $oCell = new Cell('section', 1); + $element = $oCell->addPreserveText('text'); + } + + /** + * Add text run + */ public function testCreateTextRun() { $oCell = new Cell('section', 1); @@ -202,16 +292,21 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); } + /** + * Add check box + */ public function testAddCheckBox() { $oCell = new Cell('section', 1); - $element = $oCell->addCheckBox('check1', 'text'); + $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\CheckBox', $element); } - + /** + * Get elements + */ public function testGetElements() { $oCell = new Cell('section', 1); diff --git a/tests/PhpWord/Tests/Section/TextRunTest.php b/tests/PhpWord/Tests/Section/TextRunTest.php index dea3fcdd..32b6d4dc 100644 --- a/tests/PhpWord/Tests/Section/TextRunTest.php +++ b/tests/PhpWord/Tests/Section/TextRunTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\TextRun; /** * Test class for PhpOffice\PhpWord\Section\TextRun * - * @coversDefaultClass \PhpOffice\PhpWord\Section\TextRun * @runTestsInSeparateProcesses */ class TextRunTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstructNull() { $oTextRun = new TextRun(); @@ -28,6 +30,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTextRun->getParagraphStyle(), null); } + /** + * New instance with string + */ public function testConstructString() { $oTextRun = new TextRun('pStyle'); @@ -37,6 +42,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTextRun->getParagraphStyle(), 'pStyle'); } + /** + * New instance with array + */ public function testConstructArray() { $oTextRun = new TextRun(array('spacing' => 100)); @@ -46,6 +54,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } + /** + * Add text + */ public function testAddText() { $oTextRun = new TextRun(); @@ -56,6 +67,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'text'); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oTextRun = new TextRun(); @@ -66,6 +80,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add link + */ public function testAddLink() { $oTextRun = new TextRun(); @@ -76,6 +93,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getLinkSrc(), 'http://www.google.fr'); } + /** + * Add link with name + */ public function testAddLinkWithName() { $oTextRun = new TextRun(); @@ -87,6 +107,20 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertEquals($element->getLinkName(), 'ééé'); } + /** + * Add text break + */ + public function testAddTextBreak() + { + $oTextRun = new TextRun(); + $element = $oTextRun->addTextBreak(2); + + $this->assertCount(2, $oTextRun->getElements()); + } + + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -98,6 +132,9 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oTextRun->getElements()); } + /** + * Add footnote + */ public function testCreateFootnote() { $oTextRun = new TextRun(); diff --git a/tests/PhpWord/Tests/Section/TextTest.php b/tests/PhpWord/Tests/Section/TextTest.php index 4124f27a..5811c735 100644 --- a/tests/PhpWord/Tests/Section/TextTest.php +++ b/tests/PhpWord/Tests/Section/TextTest.php @@ -10,15 +10,18 @@ namespace PhpOffice\PhpWord\Tests\Section; use PhpOffice\PhpWord\Section\Text; +use PhpOffice\PhpWord\Style\Font; /** * Test class for PhpOffice\PhpWord\Section\Text * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Text * @runTestsInSeparateProcesses */ class TextTest extends \PHPUnit_Framework_TestCase { + /** + * New instance + */ public function testConstruct() { $oText = new Text(); @@ -29,6 +32,9 @@ class TextTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } + /** + * Get text + */ public function testText() { $oText = new Text('text'); @@ -36,6 +42,9 @@ class TextTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oText->getText(), 'text'); } + /** + * Get font style + */ public function testFont() { $oText = new Text('text', 'fontStyle'); @@ -45,6 +54,19 @@ class TextTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); } + /** + * Get font style as object + */ + public function testFontObject() + { + $font = new Font(); + $oText = new Text('text', $font); + $this->assertEquals($oText->getFontStyle(), $font); + } + + /** + * Get paragraph style + */ public function testParagraph() { $oText = new Text('text', 'fontStyle', 'paragraphStyle'); diff --git a/tests/PhpWord/Tests/SectionTest.php b/tests/PhpWord/Tests/SectionTest.php index e6205db3..48b5bb73 100644 --- a/tests/PhpWord/Tests/SectionTest.php +++ b/tests/PhpWord/Tests/SectionTest.php @@ -88,7 +88,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section->addTitle(utf8_decode('ä'), 1); $section->createTextRun(); $section->createFootnote(); - $section->addCheckBox('check1', utf8_decode('ä')); + $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); $section->addTOC(); $elementCollection = $section->getElements(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php index f0b44e0b..5318ac81 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Tests\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** @@ -33,7 +34,11 @@ class DocumentTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->createSection(); - $section->getSettings()->setPageNumberingStart(2); + $settings = $section->getSettings(); + $settings->setLandscape(); + $settings->setPageNumberingStart(2); + $settings->setBorderSize(240); + $settings->setBreakType('nextPage'); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); @@ -85,4 +90,39 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $element = $doc->getElement('/w:document/w:body/w:p[11]/w:r/w:object/o:OLEObject'); $this->assertEquals('Embed', $element->getAttribute('Type')); } + + /** + * Write element with some styles + */ + public function testElementStyles() + { + $objectSrc = __DIR__ . "/../../_files/documents/sheet.xls"; + + $phpWord = new PhpWord(); + $phpWord->addParagraphStyle('pStyle', array('align' => 'center')); + $phpWord->addFontStyle('fStyle', array('size' => '20')); + $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); + $fontStyle = new Font('text', array('align' => 'center')); + $section = $phpWord->createSection(); + $section->addListItem('List Item', 0, null, null, 'pStyle'); + $section->addObject($objectSrc, array('align' => 'center')); + $section->addTOC($fontStyle); + $section->addTitle('Title 1', 1); + $section->addTOC('fStyle'); + $doc = TestHelperDOCX::getDocument($phpWord); + + // List item + $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId'); + $this->assertEquals(3, $element->getAttribute('w:val')); + + // Object + $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject'); + $this->assertEquals('Embed', $element->getAttribute('Type')); + + // TOC + $element = $doc->getElement('/w:document/w:body/w:p[3]/w:pPr/w:tabs/w:tab'); + $this->assertEquals('right', $element->getAttribute('w:val')); + $this->assertEquals('dot', $element->getAttribute('w:leader')); + $this->assertEquals(9062, $element->getAttribute('w:pos')); + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php index 06906b41..a1220d26 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php @@ -30,11 +30,15 @@ class FootnotesTest extends \PHPUnit_Framework_TestCase public function testWriteFootnotes() { $phpWord = new PhpWord(); + $phpWord->addParagraphStyle('pStyle', array('align' => 'left')); $section = $phpWord->createSection(); $section->addText('Text'); - $footnote = $section->createFootnote(); - $footnote->addText('Footnote'); - $footnote->addLink('http://google.com'); + $footnote1 = $section->createFootnote('pStyle'); + $footnote1->addText('Footnote'); + $footnote1->addTextBreak(); + $footnote1->addLink('http://google.com'); + $footnote2 = $section->createFootnote(array('align' => 'left')); + $footnote2->addText('Footnote'); $doc = TestHelperDOCX::getDocument($phpWord); $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:footnoteReference")); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index 22a1c0df..fa4e301c 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -99,6 +99,8 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $section = $phpWord->createSection(); $section->addText('Test'); + $footnote = $section->createFootnote(); + $footnote->addText('Test'); $writer = new Word2007($phpWord); $writer->setUseDiskCaching(true); From 0e2f476cc2818aaad12be1076efd2ed792d9d3be Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 14:15:23 +0700 Subject: [PATCH 025/146] Docblock updates --- samples/Sample_Footer.php | 6 +- samples/Sample_Header.php | 10 +-- src/PhpWord/Section.php | 5 +- src/PhpWord/Section/CheckBox.php | 6 +- src/PhpWord/Section/Table/Cell.php | 5 +- src/PhpWord/Writer/Word2007/Base.php | 3 + .../Tests/Exceptions/ExceptionTest.php | 2 + .../Exceptions/InvalidImageExceptionTest.php | 2 + .../Exceptions/InvalidStyleExceptionTest.php | 2 + .../UnsupportedImageTypeExceptionTest.php | 2 + tests/PhpWord/Tests/Reader/Word2007Test.php | 5 ++ .../Tests/Section/Footer/PreserveTextTest.php | 10 ++- tests/PhpWord/Tests/Section/LinkTest.php | 12 ++++ tests/PhpWord/Tests/Section/ListItemTest.php | 9 +++ tests/PhpWord/Tests/Section/ObjectTest.php | 18 ++++++ tests/PhpWord/Tests/Section/SettingsTest.php | 34 +++++++++- tests/PhpWord/Tests/Section/Table/RowTest.php | 9 +++ tests/PhpWord/Tests/Section/TableTest.php | 18 ++++++ tests/PhpWord/Tests/Section/TitleTest.php | 15 +++++ tests/PhpWord/Tests/Shared/StringTest.php | 9 +++ tests/PhpWord/Tests/Style/FontTest.php | 4 +- tests/PhpWord/Tests/Style/ParagraphTest.php | 7 ++- tests/PhpWord/Tests/TemplateTest.php | 1 + .../Tests/Writer/Word2007/FooterTest.php | 2 + .../Tests/Writer/Word2007/FootnotesTest.php | 3 + .../Tests/Writer/Word2007/HeaderTest.php | 3 +- .../Tests/_includes/TestHelperDOCX.php | 26 +++++++- tests/PhpWord/Tests/_includes/XmlDocument.php | 63 ++++++++++++++++--- tests/bootstrap.php | 11 +++- 29 files changed, 271 insertions(+), 31 deletions(-) diff --git a/samples/Sample_Footer.php b/samples/Sample_Footer.php index 5c7d7da1..4d5777c2 100644 --- a/samples/Sample_Footer.php +++ b/samples/Sample_Footer.php @@ -3,7 +3,7 @@ * Footer file */ // Do not show execution time for index -if (!$isIndexFile) { +if (!IS_INDEX) { echo date('H:i:s'), " Done writing file(s)", EOL; echo date('H:i:s'), " Peak memory usage: ", (memory_get_peak_usage(true) / 1024 / 1024), " MB", EOL; } @@ -11,12 +11,12 @@ if (!$isIndexFile) { if (CLI) { echo 'The results are stored in the "results" subdirectory.', EOL; } else { - if (!$isIndexFile) { + if (!IS_INDEX) { $types = array('docx', 'odt', 'rtf'); echo '

 

'; echo '

{$pageHeading}

"; +$pageHeading = IS_INDEX ? '' : "

{$pageHeading}

"; // Populate samples $files = ''; if ($handle = opendir('.')) { diff --git a/src/PhpWord/Section.php b/src/PhpWord/Section.php index 1649ce96..e350f7f8 100644 --- a/src/PhpWord/Section.php +++ b/src/PhpWord/Section.php @@ -421,8 +421,9 @@ class Section * * @param string $name * @param string $text - * @param mixed $style - * @return PHPWord_Section_CheckBox + * @param mixed $styleFont + * @param mixed $styleParagraph + * @return \PhpOffice\PhpWord\Section\CheckBox */ public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) { diff --git a/src/PhpWord/Section/CheckBox.php b/src/PhpWord/Section/CheckBox.php index 57671b84..00f75e54 100644 --- a/src/PhpWord/Section/CheckBox.php +++ b/src/PhpWord/Section/CheckBox.php @@ -129,6 +129,8 @@ class CheckBox } /** + * Set name content + * * @param string $name * @return $this */ @@ -149,6 +151,8 @@ class CheckBox } /** + * Set text content + * * @param string $text * @return $this */ @@ -159,7 +163,7 @@ class CheckBox } /** - * Get Text content + * Get text content * * @return string */ diff --git a/src/PhpWord/Section/Table/Cell.php b/src/PhpWord/Section/Table/Cell.php index 45d43ece..e0004350 100755 --- a/src/PhpWord/Section/Table/Cell.php +++ b/src/PhpWord/Section/Table/Cell.php @@ -296,8 +296,9 @@ class Cell * * @param string $name * @param string $text - * @param mixed $style - * @return PHPWord_Section_CheckBox + * @param mixed $styleFont + * @param mixed $styleParagraph + * @return \PhpOffice\PhpWord\Section\CheckBox */ public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) { diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index c32eede3..644bf2a2 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1220,6 +1220,9 @@ class Base extends WriterPart /** * Write CheckBox + * + * @param boolean $withoutP + * @param boolean $checkState */ protected function _writeCheckBox(XMLWriter $xmlWriter, CheckBox $checkbox, $withoutP = false, $checkState = false) { diff --git a/tests/PhpWord/Tests/Exceptions/ExceptionTest.php b/tests/PhpWord/Tests/Exceptions/ExceptionTest.php index 2810c054..81732c97 100644 --- a/tests/PhpWord/Tests/Exceptions/ExceptionTest.php +++ b/tests/PhpWord/Tests/Exceptions/ExceptionTest.php @@ -20,6 +20,8 @@ use PhpOffice\PhpWord\Exceptions\Exception; class ExceptionTest extends \PHPUnit_Framework_TestCase { /** + * Throw new exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\Exception * @covers \PhpOffice\PhpWord\Exceptions\Exception */ diff --git a/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php b/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php index 4ae7c7f0..7db70993 100644 --- a/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php @@ -20,6 +20,8 @@ use PhpOffice\PhpWord\Exceptions\InvalidImageException; class InvalidImageExceptionTest extends \PHPUnit_Framework_TestCase { /** + * Throw new exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidImageException * @covers \PhpOffice\PhpWord\Exceptions\InvalidImageException */ diff --git a/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php b/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php index bb782edc..174e07ac 100644 --- a/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php @@ -20,6 +20,8 @@ use PhpOffice\PhpWord\Exceptions\InvalidStyleException; class InvalidStyleExceptionTest extends \PHPUnit_Framework_TestCase { /** + * Throw new exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException * @covers \PhpOffice\PhpWord\Exceptions\InvalidStyleException */ diff --git a/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php index ab0d25cc..027ec3a9 100644 --- a/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php @@ -20,6 +20,8 @@ use PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException; class UnsupportedImageTypeExceptionTest extends \PHPUnit_Framework_TestCase { /** + * Throw new exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException * @covers \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException */ diff --git a/tests/PhpWord/Tests/Reader/Word2007Test.php b/tests/PhpWord/Tests/Reader/Word2007Test.php index 768f6b6e..5aee8144 100644 --- a/tests/PhpWord/Tests/Reader/Word2007Test.php +++ b/tests/PhpWord/Tests/Reader/Word2007Test.php @@ -41,6 +41,8 @@ class Word2007Test extends \PHPUnit_Framework_TestCase } /** + * Can read exception + * * @expectedException \PhpOffice\PhpWord\Exceptions\Exception */ public function testCanReadFailed() @@ -54,6 +56,9 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $object = IOFactory::load($fqFilename); } + /** + * Load + */ public function testLoad() { $fqFilename = join( diff --git a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php b/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php index e78d2100..82ded881 100644 --- a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php @@ -14,11 +14,13 @@ use PhpOffice\PhpWord\Section\Footer\PreserveText; /** * Test class for PhpOffice\PhpWord\Section\Footer\PreserveText * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Footer\PreserveText * @runTestsInSeparateProcesses */ class PreserveTextTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance + */ public function testConstruct() { $oPreserveText = new PreserveText(); @@ -29,6 +31,9 @@ class PreserveTextTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oPreserveText->getParagraphStyle(), null); } + /** + * Create new instance with style name + */ public function testConstructWithString() { $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph'); @@ -37,6 +42,9 @@ class PreserveTextTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oPreserveText->getParagraphStyle(), 'styleParagraph'); } + /** + * Create new instance with array + */ public function testConstructWithArray() { $oPreserveText = new PreserveText( diff --git a/tests/PhpWord/Tests/Section/LinkTest.php b/tests/PhpWord/Tests/Section/LinkTest.php index 2e7c05b0..ae1a3e09 100644 --- a/tests/PhpWord/Tests/Section/LinkTest.php +++ b/tests/PhpWord/Tests/Section/LinkTest.php @@ -20,6 +20,9 @@ use PhpOffice\PhpWord\Style\Font; */ class LinkTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance + */ public function testConstructDefault() { $oLink = new Link('http://www.google.com'); @@ -31,6 +34,9 @@ class LinkTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oLink->getParagraphStyle(), null); } + /** + * Create new instance with array + */ public function testConstructWithParamsArray() { $oLink = new Link( @@ -47,6 +53,9 @@ class LinkTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle()); } + /** + * Create new instance with style name string + */ public function testConstructWithParamsString() { $oLink = new Link('http://www.google.com', null, 'fontStyle', 'paragraphStyle'); @@ -55,6 +64,9 @@ class LinkTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oLink->getParagraphStyle(), 'paragraphStyle'); } + /** + * Set/get relation Id + */ public function testRelationId() { $oLink = new Link('http://www.google.com'); diff --git a/tests/PhpWord/Tests/Section/ListItemTest.php b/tests/PhpWord/Tests/Section/ListItemTest.php index 42af449a..1964cdac 100644 --- a/tests/PhpWord/Tests/Section/ListItemTest.php +++ b/tests/PhpWord/Tests/Section/ListItemTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Section\ListItem; */ class ListItemTest extends \PHPUnit_Framework_TestCase { + /** + * Get text object + */ public function testText() { $oListItem = new ListItem('text'); @@ -26,6 +29,9 @@ class ListItemTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $oListItem->getTextObject()); } + /** + * Get style + */ public function testStyle() { $oListItem = new ListItem( @@ -42,6 +48,9 @@ class ListItemTest extends \PHPUnit_Framework_TestCase ); } + /** + * Get depth + */ public function testDepth() { $iVal = rand(1, 1000); diff --git a/tests/PhpWord/Tests/Section/ObjectTest.php b/tests/PhpWord/Tests/Section/ObjectTest.php index a68b6a0f..d6094de1 100644 --- a/tests/PhpWord/Tests/Section/ObjectTest.php +++ b/tests/PhpWord/Tests/Section/ObjectTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Section\Object; */ class ObjectTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance with supported files + */ public function testConstructWithSupportedFiles() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -29,6 +32,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getSource(), $src); } + /** + * Create new instance with non-supported files + */ public function testConstructWithNotSupportedFiles() { $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; @@ -39,6 +45,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getStyle(), null); } + /** + * Create with style + */ public function testConstructWithSupportedFilesAndStyle() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -49,6 +58,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getSource(), $src); } + /** + * Set/get relation Id + */ public function testRelationId() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -59,6 +71,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getRelationId(), $iVal); } + /** + * Set/get image relation Id + */ public function testImageRelationId() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -69,6 +84,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getImageRelationId(), $iVal); } + /** + * Set/get object relation Id + */ public function testObjectId() { $src = __DIR__ . "/../_files/documents/sheet.xls"; diff --git a/tests/PhpWord/Tests/Section/SettingsTest.php b/tests/PhpWord/Tests/Section/SettingsTest.php index 7c66b67a..8fb62f1c 100644 --- a/tests/PhpWord/Tests/Section/SettingsTest.php +++ b/tests/PhpWord/Tests/Section/SettingsTest.php @@ -57,6 +57,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iVal, $oSettings->getHeaderHeight()); } + /** + * Set/get margin + */ public function testMargin() { // Section Settings @@ -79,6 +82,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iVal, $oSettings->getMarginRight()); } + /** + * Set/get landscape orientation + */ public function testOrientationLandscape() { // Section Settings @@ -90,6 +96,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(11906, $oSettings->getPageSizeH()); } + /** + * Set/get portrait orientation + */ public function testOrientationPortrait() { // Section Settings @@ -101,6 +110,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(16838, $oSettings->getPageSizeH()); } + /** + * Set/get border size + */ public function testBorderSize() { // Section Settings @@ -131,6 +143,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iVal, $oSettings->getBorderTopSize()); } + /** + * Set/get border color + */ public function testBorderColor() { // Section Settings @@ -156,6 +171,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals('22FF33', $oSettings->getBorderTopColor()); } + /** + * Set/get page numbering start + */ public function testNumberingStart() { // Section Settings @@ -171,9 +189,11 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertNull($oSettings->getPageNumberingStart()); } + /** + * Set/get header height + */ public function testHeader() { - // Section Settings $oSettings = new Settings(); $this->assertEquals(720, $oSettings->getHeaderHeight()); @@ -186,6 +206,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getHeaderHeight()); } + /** + * Set/get footer height + */ public function testFooter() { // Section Settings @@ -201,6 +224,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getFooterHeight()); } + /** + * Set/get column number + */ public function testColumnsNum() { // Section Settings @@ -217,6 +243,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, $oSettings->getColsNum()); } + /** + * Set/get column spacing + */ public function testColumnsSpace() { // Section Settings @@ -233,6 +262,9 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getColsSpace()); } + /** + * Set/get break type + */ public function testBreakType() { // Section Settings diff --git a/tests/PhpWord/Tests/Section/Table/RowTest.php b/tests/PhpWord/Tests/Section/Table/RowTest.php index 991d8a47..10d53915 100644 --- a/tests/PhpWord/Tests/Section/Table/RowTest.php +++ b/tests/PhpWord/Tests/Section/Table/RowTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Section\Table\Row; */ class RowTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance + */ public function testConstruct() { $iVal = rand(1, 1000); @@ -31,6 +34,9 @@ class RowTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } + /** + * Create new instance with parameters + */ public function testConstructWithParams() { $iVal = rand(1, 1000); @@ -46,6 +52,9 @@ class RowTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } + /** + * Add cell + */ public function testAddCell() { $oRow = new Row('section', 1); diff --git a/tests/PhpWord/Tests/Section/TableTest.php b/tests/PhpWord/Tests/Section/TableTest.php index c6d3463d..9808485d 100644 --- a/tests/PhpWord/Tests/Section/TableTest.php +++ b/tests/PhpWord/Tests/Section/TableTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Section\Table; */ class TableTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance + */ public function testConstruct() { $oTable = new Table('section', 1); @@ -30,6 +33,9 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertCount(0, $oTable->getRows()); } + /** + * Get style name + */ public function testStyleText() { $oTable = new Table('section', 1, 'tableStyle'); @@ -37,6 +43,9 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTable->getStyle(), 'tableStyle'); } + /** + * Get style array + */ public function testStyleArray() { $oTable = new Table( @@ -48,6 +57,9 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle()); } + /** + * Set/get width + */ public function testWidth() { $oTable = new Table('section', 1); @@ -56,6 +68,9 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTable->getWidth(), $iVal); } + /** + * Add/get row + */ public function testRow() { $oTable = new Table('section', 1); @@ -64,6 +79,9 @@ class TableTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oTable->getRows()); } + /** + * Add cell + */ public function testCell() { $oTable = new Table('section', 1); diff --git a/tests/PhpWord/Tests/Section/TitleTest.php b/tests/PhpWord/Tests/Section/TitleTest.php index e1b25e3a..a63d184c 100644 --- a/tests/PhpWord/Tests/Section/TitleTest.php +++ b/tests/PhpWord/Tests/Section/TitleTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Section\Title; */ class TitleTest extends \PHPUnit_Framework_TestCase { + /** + * Create new instance + */ public function testConstruct() { $oTitle = new Title('text'); @@ -27,6 +30,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getText(), 'text'); } + /** + * Get style null + */ public function testStyleNull() { $oTitle = new Title('text'); @@ -34,6 +40,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getStyle(), null); } + /** + * Get style not null + */ public function testStyleNotNull() { $oTitle = new Title('text', 1, 'style'); @@ -41,6 +50,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getStyle(), 'style'); } + /** + * Get anchor + */ public function testAnchor() { $oTitle = new Title('text'); @@ -50,6 +62,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getAnchor(), $iVal); } + /** + * Get bookmark Id + */ public function testBookmarkID() { $oTitle = new Title('text'); diff --git a/tests/PhpWord/Tests/Shared/StringTest.php b/tests/PhpWord/Tests/Shared/StringTest.php index bb7a36ad..02b4898a 100644 --- a/tests/PhpWord/Tests/Shared/StringTest.php +++ b/tests/PhpWord/Tests/Shared/StringTest.php @@ -19,6 +19,9 @@ use PhpOffice\PhpWord\Shared\String; */ class StringTest extends \PHPUnit_Framework_TestCase { + /** + * Is UTF8 + */ public function testIsUTF8() { $this->assertTrue(String::isUTF8('')); @@ -26,12 +29,18 @@ class StringTest extends \PHPUnit_Framework_TestCase $this->assertFalse(String::isUTF8(utf8_decode('éééé'))); } + /** + * OOXML to PHP control character + */ public function testControlCharacterOOXML2PHP() { $this->assertEquals('', String::controlCharacterOOXML2PHP('')); $this->assertEquals(chr(0x08), String::controlCharacterOOXML2PHP('_x0008_')); } + /** + * PHP to OOXML control character + */ public function testControlCharacterPHP2OOXML() { $this->assertEquals('', String::controlCharacterPHP2OOXML('')); diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index c5e0664b..ed4d61db 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -16,11 +16,13 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Style\Font * - * @coversDefaultClass \PhpOffice\PhpWord\Style\Font * @runTestsInSeparateProcesses */ class FontTest extends \PHPUnit_Framework_TestCase { + /** + * Tear down after each test + */ public function tearDown() { TestHelperDOCX::clear(); diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 856e2b13..619d5497 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -17,11 +17,13 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Style\Paragraph * - * @coversDefaultClass \PhpOffice\PhpWord\Style\Paragraph * @runTestsInSeparateProcesses */ class ParagraphTest extends \PHPUnit_Framework_TestCase { + /** + * Tear down after each test + */ public function tearDown() { TestHelperDOCX::clear(); @@ -97,6 +99,9 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Tabs', $object->getTabs()); } + /** + * Line height + */ public function testLineHeight() { $phpWord = new PhpWord(); diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index b9302f7e..669ae946 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -65,6 +65,7 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase /** * XSL stylesheet can be applied * + * @param string $actualDocumentFqfn * @covers ::applyXslStyleSheet * @depends testTemplateCanBeSavedInTemporaryLocation * @test diff --git a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php index de08ff9d..6d303a0a 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php @@ -21,6 +21,8 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; class FooterTest extends \PHPUnit_Framework_TestCase { /** + * Write footer + * * @covers ::writeFooter */ public function testWriteFooter() diff --git a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php index a1220d26..6baba0ac 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php @@ -27,6 +27,9 @@ class FootnotesTest extends \PHPUnit_Framework_TestCase TestHelperDOCX::clear(); } + /** + * Write footnotes + */ public function testWriteFootnotes() { $phpWord = new PhpWord(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php index ca997b65..de3ac010 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php @@ -15,13 +15,12 @@ use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** * Test class for PhpOffice\PhpWord\Writer\Word2007\Header * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Header * @runTestsInSeparateProcesses */ class HeaderTest extends \PHPUnit_Framework_TestCase { /** - * @covers ::writeHeader + * Write header */ public function testWriteHeader() { diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 97f84ac2..3e24c4cc 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -1,15 +1,32 @@ Date: Sun, 30 Mar 2014 16:31:01 +0700 Subject: [PATCH 026/146] Refactor writers and readers - Create Writer abstract class - Inherit writers class from Writer - Inherit ODText\WriterPart from Word2007\WriterPart - Rename AbstractReader > Reader --- CHANGELOG.md | 2 + .../Reader/{AbstractReader.php => Reader.php} | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Writer/ODText.php | 173 ++-------------- src/PhpWord/Writer/ODText/Content.php | 7 +- src/PhpWord/Writer/ODText/Manifest.php | 7 +- src/PhpWord/Writer/ODText/Meta.php | 7 +- src/PhpWord/Writer/ODText/Styles.php | 7 +- src/PhpWord/Writer/ODText/WriterPart.php | 36 +--- src/PhpWord/Writer/RTF.php | 104 +++------- src/PhpWord/Writer/Word2007.php | 157 +++------------ src/PhpWord/Writer/Word2007/ContentTypes.php | 7 +- src/PhpWord/Writer/Word2007/DocProps.php | 14 +- src/PhpWord/Writer/Word2007/Document.php | 6 +- src/PhpWord/Writer/Word2007/DocumentRels.php | 14 +- src/PhpWord/Writer/Word2007/Footer.php | 7 +- src/PhpWord/Writer/Word2007/Footnotes.php | 11 +- src/PhpWord/Writer/Word2007/FootnotesRels.php | 7 +- src/PhpWord/Writer/Word2007/Header.php | 6 +- src/PhpWord/Writer/Word2007/Rels.php | 7 +- src/PhpWord/Writer/Word2007/Styles.php | 14 +- src/PhpWord/Writer/Word2007/WriterPart.php | 30 ++- src/PhpWord/Writer/Writer.php | 184 ++++++++++++++++++ 23 files changed, 310 insertions(+), 501 deletions(-) rename src/PhpWord/Reader/{AbstractReader.php => Reader.php} (97%) create mode 100644 src/PhpWord/Writer/Writer.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e4cb23..f97c4c07 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Miscellaneous - Documentation: Simplify page level docblock - @ivanlanin GH-179 +- Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 +- Reader: Rename AbstractReader > Reader - @ivanlanin ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/Reader.php similarity index 97% rename from src/PhpWord/Reader/AbstractReader.php rename to src/PhpWord/Reader/Reader.php index e70bea94..153a4013 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/Reader.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Exceptions\Exception; * * @codeCoverageIgnore Abstract class */ -abstract class AbstractReader implements IReader +abstract class Reader implements IReader { /** * Read data only? diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index b5e679f2..78720237 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Exceptions\Exception; /** * Reader for Word2007 */ -class Word2007 extends AbstractReader implements IReader +class Word2007 extends Reader implements IReader { /** * Can the current IReader read the file? diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index fe275838..8c58df60 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -21,42 +21,14 @@ use PhpOffice\PhpWord\Writer\ODText\Styles; /** * ODText writer */ -class ODText implements IWriter +class ODText extends Writer implements IWriter { - /** - * PHPWord object - * - * @var \PhpOffice\PhpWord\PhpWord - */ - private $_document; - - /** - * Individual writers - * - * @var \PhpOffice\PhpWord\Writer\ODText\WriterPart[] - */ - private $_writerParts; - /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * * @var \PhpOffice\PhpWord\HashTable */ - private $_drawingHashTable; - - /** - * Use disk caching where possible? - * - * @var boolean - */ - private $_useDiskCaching = false; - - /** - * Disk caching directory - * - * @var string - */ - private $_diskCachingDirectory; + private $drawingHashTable; /** * Create new ODText writer @@ -67,24 +39,18 @@ class ODText implements IWriter // Assign PhpWord $this->setPhpWord($phpWord); - // Set up disk caching location - $this->_diskCachingDirectory = './'; - - // Initialise writer parts - $this->_writerParts['content'] = new Content(); - $this->_writerParts['manifest'] = new Manifest(); - $this->_writerParts['meta'] = new Meta(); - $this->_writerParts['mimetype'] = new Mimetype(); - $this->_writerParts['styles'] = new Styles(); - - - // Assign parent IWriter - foreach ($this->_writerParts as $writer) { + // Set writer parts + $this->writerParts['content'] = new Content(); + $this->writerParts['manifest'] = new Manifest(); + $this->writerParts['meta'] = new Meta(); + $this->writerParts['mimetype'] = new Mimetype(); + $this->writerParts['styles'] = new Styles(); + foreach ($this->writerParts as $writer) { $writer->setParentWriter($this); } // Set HashTable variables - $this->_drawingHashTable = new HashTable(); + $this->drawingHashTable = new HashTable(); } /** @@ -95,17 +61,8 @@ class ODText implements IWriter */ public function save($pFilename = null) { - if (!is_null($this->_document)) { - // If $pFilename is php://output or php://stdout, make it a temporary file... - $originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { - $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_'); - if ($pFilename == '') { - $pFilename = $originalFilename; - } - } - - // Create drawing dictionary + if (!is_null($this->phpWord)) { + $pFilename = $this->getTempFile($pFilename); // Create new ZIP file and open it for writing $objZip = new \ZipArchive(); @@ -119,19 +76,19 @@ class ODText implements IWriter // Add mimetype to ZIP file //@todo Not in \ZipArchive::CM_STORE mode - $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype($this->_document)); + $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype($this->phpWord)); // Add content.xml to ZIP file - $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->_document)); + $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord)); // Add meta.xml to ZIP file - $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->_document)); + $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord)); // Add styles.xml to ZIP file - $objZip->addFromString('styles.xml', $this->getWriterPart('styles')->writeStyles($this->_document)); + $objZip->addFromString('styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); // Add META-INF/manifest.xml - $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->_document)); + $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->phpWord)); // Add media. Has not used yet. Legacy from PHPExcel. // @codeCoverageIgnoreStart @@ -173,46 +130,12 @@ class ODText implements IWriter throw new Exception("Could not close zip file $pFilename."); } - // If a temporary file was used, copy it to the correct file stream - if ($originalFilename != $pFilename) { - if (copy($pFilename, $originalFilename) === false) { - throw new Exception("Could not copy temporary zip file $pFilename to $originalFilename."); - } - @unlink($pFilename); - } - + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } } - /** - * Get PhpWord object - * - * @return \PhpOffice\PhpWord\PhpWord - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function getPhpWord() - { - if (!is_null($this->_document)) { - return $this->_document; - } else { - throw new Exception("No PhpWord assigned."); - } - } - - /** - * Set PhpWord object - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return \PhpOffice\PhpWord\Writer\ODText - */ - public function setPhpWord(PhpWord $phpWord = null) - { - $this->_document = $phpWord; - return $this; - } - /** * Get PHPWord_Worksheet_BaseDrawing HashTable * @@ -220,64 +143,6 @@ class ODText implements IWriter */ public function getDrawingHashTable() { - return $this->_drawingHashTable; - } - - /** - * Get writer part - * - * @param string $pPartName Writer part name - * @return \PhpOffice\PhpWord\Writer\ODText\WriterPart - */ - public function getWriterPart($pPartName = '') - { - if ($pPartName != '' && isset($this->_writerParts[strtolower($pPartName)])) { - return $this->_writerParts[strtolower($pPartName)]; - } else { - return null; - } - } - - /** - * Get use disk caching where possible? - * - * @return boolean - */ - public function getUseDiskCaching() - { - return $this->_useDiskCaching; - } - - /** - * Set use disk caching where possible? - * - * @param boolean $pValue - * @param string $pDirectory Disk caching directory - * @throws \PhpOffice\PhpWord\Exceptions\Exception Exception when directory does not exist - * @return \PhpOffice\PhpWord\Writer\ODText - */ - public function setUseDiskCaching($pValue = false, $pDirectory = null) - { - $this->_useDiskCaching = $pValue; - - if (!is_null($pDirectory)) { - if (is_dir($pDirectory)) { - $this->_diskCachingDirectory = $pDirectory; - } else { - throw new Exception("Directory does not exist: $pDirectory"); - } - } - - return $this; - } - - /** - * Get disk caching directory - * - * @return string - */ - public function getDiskCachingDirectory() - { - return $this->_diskCachingDirectory; + return $this->drawingHashTable; } } diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 44ac7bab..4e75068d 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -41,12 +41,7 @@ class Content extends WriterPart public function writeContent(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index f1c652ca..cb92ddcc 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -27,12 +27,7 @@ class Manifest extends WriterPart public function writeManifest(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index 69cc5aea..fdd0ec7c 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -26,12 +26,7 @@ class Meta extends WriterPart public function writeMeta(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index f2d46c6a..6a91a7e2 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -30,12 +30,7 @@ class Styles extends WriterPart public function writeStyles(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); diff --git a/src/PhpWord/Writer/ODText/WriterPart.php b/src/PhpWord/Writer/ODText/WriterPart.php index 66531136..a6fa93cb 100644 --- a/src/PhpWord/Writer/ODText/WriterPart.php +++ b/src/PhpWord/Writer/ODText/WriterPart.php @@ -9,43 +9,9 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\Exceptions\Exception; -use PhpOffice\PhpWord\Writer\IWriter; - /** * ODText writer part abstract */ -abstract class WriterPart +abstract class WriterPart extends \PhpOffice\PhpWord\Writer\Word2007\WriterPart { - /** - * Parent IWriter object - * - * @var \PhpOffice\PhpWord\Writer\IWriter - */ - private $_parentWriter; - - /** - * Set parent IWriter object - * - * @param \PhpOffice\PhpWord\Writer\IWriter $pWriter - */ - public function setParentWriter(IWriter $pWriter = null) - { - $this->_parentWriter = $pWriter; - } - - /** - * Get parent IWriter object - * - * @return \PhpOffice\PhpWord\Writer\IWriter - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function getParentWriter() - { - if (!is_null($this->_parentWriter)) { - return $this->_parentWriter; - } else { - throw new Exception("No parent IWriter assigned."); - } - } } diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 017c89c1..d7fc7101 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -31,42 +31,35 @@ use PhpOffice\PhpWord\TOC; /** * RTF writer */ -class RTF implements IWriter +class RTF extends Writer implements IWriter { - /** - * Private PhpWord - * - * @var \PhpOffice\PhpWord\PhpWord - */ - private $_document; - /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * * @var \PhpOffice\PhpWord\HashTable */ - private $_drawingHashTable; + private $drawingHashTable; /** * Color register * * @var array */ - private $_colorTable; + private $colorTable; /** * Font register * * @var array */ - private $_fontTable; + private $fontTable; /** * Last paragraph style * * @var mixed */ - private $_lastParagraphStyle; + private $lastParagraphStyle; /** * Create new RTF writer @@ -78,7 +71,7 @@ class RTF implements IWriter $this->setPhpWord($phpWord); // Set HashTable variables - $this->_drawingHashTable = new HashTable(); + $this->drawingHashTable = new HashTable(); } /** @@ -89,60 +82,19 @@ class RTF implements IWriter */ public function save($pFilename = null) { - if (!is_null($this->_document)) { - // If $pFilename is php://output or php://stdout, make it a temporary file... - $originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { - $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_'); - if ($pFilename == '') { - $pFilename = $originalFilename; - } - } + if (!is_null($this->phpWord)) { + $pFilename = $this->getTempFile($pFilename); $hFile = fopen($pFilename, 'w') or die("can't open file"); fwrite($hFile, $this->getData()); fclose($hFile); - // If a temporary file was used, copy it to the correct file stream - if ($originalFilename != $pFilename) { - if (copy($pFilename, $originalFilename) === false) { - throw new Exception("Could not copy temporary zip file $pFilename to $originalFilename."); - } - @unlink($pFilename); - } - + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } } - /** - * Get PhpWord object - * - * @return \PhpOffice\PhpWord\PhpWord - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function getPhpWord() - { - if (!is_null($this->_document)) { - return $this->_document; - } else { - throw new Exception("No PhpWord assigned."); - } - } - - /** - * Set PhpWord object - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return \PhpOffice\PhpWord\Writer\RTF - */ - public function setPhpWord(PhpWord $phpWord = null) - { - $this->_document = $phpWord; - return $this; - } - /** * Get PHPWord_Worksheet_BaseDrawing HashTable * @@ -150,7 +102,7 @@ class RTF implements IWriter */ public function getDrawingHashTable() { - return $this->_drawingHashTable; + return $this->drawingHashTable; } /** @@ -160,9 +112,9 @@ class RTF implements IWriter */ private function getData() { - // PhpWord object : $this->_document - $this->_fontTable = $this->getDataFont(); - $this->_colorTable = $this->getDataColor(); + // PhpWord object : $this->phpWord + $this->fontTable = $this->getDataFont(); + $this->colorTable = $this->getDataColor(); $sRTFContent = '{\rtf1'; // Set the default character set @@ -174,13 +126,13 @@ class RTF implements IWriter $sRTFContent .= \PHP_EOL; // Set the font tbl group $sRTFContent .= '{\fonttbl'; - foreach ($this->_fontTable as $idx => $font) { + foreach ($this->fontTable as $idx => $font) { $sRTFContent .= '{\f' . $idx . '\fnil\fcharset0 ' . $font . ';}'; } $sRTFContent .= '}' . \PHP_EOL; // Set the color tbl group $sRTFContent .= '{\colortbl '; - foreach ($this->_colorTable as $idx => $color) { + foreach ($this->colorTable as $idx => $color) { $arrColor = Drawing::htmlToRGB($color); $sRTFContent .= ';\red' . $arrColor[0] . '\green' . $arrColor[1] . '\blue' . $arrColor[2] . ''; } @@ -218,12 +170,12 @@ class RTF implements IWriter */ private function getDataFont() { - $phpWord = $this->_document; + $phpWord = $this->phpWord; $arrFonts = array(); // Default font : PhpWord::DEFAULT_FONT_NAME $arrFonts[] = PhpWord::DEFAULT_FONT_NAME; - // PhpWord object : $this->_document + // PhpWord object : $this->phpWord // Browse styles $styles = Style::getStyles(); @@ -273,10 +225,10 @@ class RTF implements IWriter */ private function getDataColor() { - $phpWord = $this->_document; + $phpWord = $this->phpWord; $arrColors = array(); - // PhpWord object : $this->_document + // PhpWord object : $this->phpWord // Browse styles $styles = Style::getStyles(); @@ -334,7 +286,7 @@ class RTF implements IWriter */ private function getDataContent() { - $phpWord = $this->_document; + $phpWord = $this->phpWord; $sRTFBody = ''; $_sections = $phpWord->getSections(); @@ -400,7 +352,7 @@ class RTF implements IWriter } if ($styleParagraph && !$withoutP) { - if ($this->_lastParagraphStyle != $text->getParagraphStyle()) { + if ($this->lastParagraphStyle != $text->getParagraphStyle()) { $sRTFText .= '\pard\nowidctlpar'; if ($styleParagraph->getSpaceAfter() != null) { $sRTFText .= '\sa' . $styleParagraph->getSpaceAfter(); @@ -410,17 +362,17 @@ class RTF implements IWriter $sRTFText .= '\qc'; } } - $this->_lastParagraphStyle = $text->getParagraphStyle(); + $this->lastParagraphStyle = $text->getParagraphStyle(); } else { - $this->_lastParagraphStyle = ''; + $this->lastParagraphStyle = ''; } } else { - $this->_lastParagraphStyle = ''; + $this->lastParagraphStyle = ''; } if ($styleFont instanceof Font) { if ($styleFont->getColor() != null) { - $idxColor = array_search($styleFont->getColor(), $this->_colorTable); + $idxColor = array_search($styleFont->getColor(), $this->colorTable); if ($idxColor !== false) { $sRTFText .= '\cf' . ($idxColor + 1); } @@ -428,7 +380,7 @@ class RTF implements IWriter $sRTFText .= '\cf0'; } if ($styleFont->getName() != null) { - $idxFont = array_search($styleFont->getName(), $this->_fontTable); + $idxFont = array_search($styleFont->getName(), $this->fontTable); if ($idxFont !== false) { $sRTFText .= '\f' . $idxFont; } @@ -445,7 +397,7 @@ class RTF implements IWriter $sRTFText .= '\fs' . ($styleFont->getSize() * 2); } } - if ($this->_lastParagraphStyle != '' || $styleFont) { + if ($this->lastParagraphStyle != '' || $styleFont) { $sRTFText .= ' '; } $sRTFText .= $text->getText(); @@ -501,7 +453,7 @@ class RTF implements IWriter */ private function getDataContentTextBreak() { - $this->_lastParagraphStyle = ''; + $this->lastParagraphStyle = ''; return '\par' . \PHP_EOL; } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 5b4f9f85..6ceed4fb 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -27,36 +27,8 @@ use PhpOffice\PhpWord\Writer\Word2007\Styles; /** * Word2007 writer */ -class Word2007 implements IWriter +class Word2007 extends Writer implements IWriter { - /** - * PHPWord object - * - * @var PhpOffice\PhpWord\PhpWord - */ - private $_document; - - /** - * Individual writers - * - * @var PhpOffice\PhpWord\Writer\Word2007\WriterPart - */ - private $_writerParts; - - /** - * Disk caching directory - * - * @var string - */ - private $_diskCachingDirectory; - - /** - * Use disk caching - * - * @var boolean - */ - private $_useDiskCaching = false; - /** * Types of images * @@ -78,22 +50,21 @@ class Word2007 implements IWriter */ public function __construct(PhpWord $phpWord = null) { - $this->_document = $phpWord; + // Assign PhpWord + $this->setPhpWord($phpWord); - $this->_diskCachingDirectory = './'; - - $this->_writerParts['contenttypes'] = new ContentTypes(); - $this->_writerParts['rels'] = new Rels(); - $this->_writerParts['docprops'] = new DocProps(); - $this->_writerParts['documentrels'] = new DocumentRels(); - $this->_writerParts['document'] = new Document(); - $this->_writerParts['styles'] = new Styles(); - $this->_writerParts['header'] = new Header(); - $this->_writerParts['footer'] = new Footer(); - $this->_writerParts['footnotes'] = new Footnotes(); - $this->_writerParts['footnotesrels'] = new FootnotesRels(); - - foreach ($this->_writerParts as $writer) { + // Set writer parts + $this->writerParts['contenttypes'] = new ContentTypes(); + $this->writerParts['rels'] = new Rels(); + $this->writerParts['docprops'] = new DocProps(); + $this->writerParts['documentrels'] = new DocumentRels(); + $this->writerParts['document'] = new Document(); + $this->writerParts['styles'] = new Styles(); + $this->writerParts['header'] = new Header(); + $this->writerParts['footer'] = new Footer(); + $this->writerParts['footnotes'] = new Footnotes(); + $this->writerParts['footnotesrels'] = new FootnotesRels(); + foreach ($this->writerParts as $writer) { $writer->setParentWriter($this); } } @@ -105,16 +76,8 @@ class Word2007 implements IWriter */ public function save($pFilename = null) { - if (!is_null($this->_document)) { - - // If $pFilename is php://output or php://stdout, make it a temporary file... - $originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { - $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_'); - if ($pFilename == '') { - $pFilename = $originalFilename; - } - } + if (!is_null($this->phpWord)) { + $pFilename = $this->getTempFile($pFilename); // Create new ZIP file and open it for writing $objZip = new \ZipArchive(); @@ -126,12 +89,11 @@ class Word2007 implements IWriter } } - $sectionElements = array(); $_secElements = Media::getSectionMediaElements(); foreach ($_secElements as $element) { // loop through section media elements if ($element['type'] != 'hyperlink') { - $this->_addFileToPackage($objZip, $element); + $this->addFileToPackage($objZip, $element); } $sectionElements[] = $element; } @@ -141,7 +103,7 @@ class Word2007 implements IWriter if (count($_hdrMedia) > 0) { $objZip->addFromString('word/_rels/' . $_headerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_hdrMedia)); foreach ($_hdrMedia as $element) { // loop through header media elements - $this->_addFileToPackage($objZip, $element); + $this->addFileToPackage($objZip, $element); } } } @@ -151,7 +113,7 @@ class Word2007 implements IWriter if (count($_ftrMedia) > 0) { $objZip->addFromString('word/_rels/' . $_footerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_ftrMedia)); foreach ($_ftrMedia as $element) { // loop through footers media elements - $this->_addFileToPackage($objZip, $element); + $this->addFileToPackage($objZip, $element); } } } @@ -166,7 +128,7 @@ class Word2007 implements IWriter $_cHdrs = 0; $_cFtrs = 0; $rID = Media::countSectionMediaElements() + 6; - $_sections = $this->_document->getSections(); + $_sections = $this->phpWord->getSections(); $footers = array(); foreach ($_sections as $section) { @@ -211,12 +173,12 @@ class Word2007 implements IWriter $footers ) ); - $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeRelationships($this->_document)); - $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->_document)); - $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->_document)); - $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->_document)); + $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeRelationships($this->phpWord)); + $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->phpWord)); + $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->phpWord)); + $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord)); $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('documentrels')->writeDocumentRels($sectionElements)); - $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->_document)); + $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); // Write static files $objZip->addFile(__DIR__ . '/../_staticDocParts/numbering.xml', 'word/numbering.xml'); @@ -225,19 +187,12 @@ class Word2007 implements IWriter $objZip->addFile(__DIR__ . '/../_staticDocParts/webSettings.xml', 'word/webSettings.xml'); $objZip->addFile(__DIR__ . '/../_staticDocParts/fontTable.xml', 'word/fontTable.xml'); - // Close file if ($objZip->close() === false) { throw new Exception("Could not close zip file $pFilename."); } - // If a temporary file was used, copy it to the correct file stream - if ($originalFilename != $pFilename) { - if (copy($pFilename, $originalFilename) === false) { - throw new Exception("Could not copy temporary zip file $pFilename to $originalFilename."); - } - @unlink($pFilename); - } + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } @@ -290,69 +245,13 @@ class Word2007 implements IWriter } } - /** - * Get writer part - * - * @param string $pPartName Writer part name - * @return \PhpOffice\PhpWord\Writer\ODText\WriterPart - */ - public function getWriterPart($pPartName = '') - { - if ($pPartName != '' && isset($this->_writerParts[strtolower($pPartName)])) { - return $this->_writerParts[strtolower($pPartName)]; - } else { - return null; - } - } - - /** - * Get use disk caching status - * - * @return boolean - */ - public function getUseDiskCaching() - { - return $this->_useDiskCaching; - } - - /** - * Set use disk caching status - * - * @param boolean $pValue - * @param string $pDirectory - */ - public function setUseDiskCaching($pValue = false, $pDirectory = null) - { - $this->_useDiskCaching = $pValue; - - if (!is_null($pDirectory)) { - if (is_dir($pDirectory)) { - $this->_diskCachingDirectory = $pDirectory; - } else { - throw new Exception("Directory does not exist: $pDirectory"); - } - } - - return $this; - } - - /** - * Get disk caching directory - * - * @return string - */ - public function getDiskCachingDirectory() - { - return $this->_diskCachingDirectory; - } - /** * Check content types * * @param mixed $objZip * @param mixed $element */ - private function _addFileToPackage($objZip, $element) + private function addFileToPackage($objZip, $element) { if (isset($element['isMemImage']) && $element['isMemImage']) { $image = call_user_func($element['createfunction'], $element['source']); diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index ea97d138..9f8c3fb2 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -27,12 +27,7 @@ class ContentTypes extends WriterPart public function writeContentTypes($_imageTypes, $_objectTypes, $_cHdrs, $footers) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 3c7d6977..591dfc0e 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -23,12 +23,7 @@ class DocProps extends WriterPart public function writeDocPropsApp(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); @@ -120,12 +115,7 @@ class DocProps extends WriterPart public function writeDocPropsCore(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index ec7d2df0..585050df 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -41,11 +41,7 @@ class Document extends Base public function writeDocument(PhpWord $phpWord = null) { // Create XML writer - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 218869b5..20a014f2 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -25,12 +25,7 @@ class DocumentRels extends WriterPart public function writeDocumentRels($_relsCollection) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); @@ -118,12 +113,7 @@ class DocumentRels extends WriterPart public function writeHeaderFooterRels($_relsCollection) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index a2ff09b4..d4f68826 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -30,12 +30,7 @@ class Footer extends Base public function writeFooter(\PhpOffice\PhpWord\Section\Footer $footer) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index eb410393..d69e0f0c 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -29,15 +29,8 @@ class Footnotes extends Base public function writeFootnotes($allFootnotesCollection) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter( - XMLWriter::STORAGE_DISK, - $this->getParentWriter()->getDiskCachingDirectory() - ); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); + // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('w:footnotes'); diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index 7f87ce30..f9e5c015 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -25,12 +25,7 @@ class FootnotesRels extends WriterPart public function writeFootnotesRels($_relsCollection) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index bdec8d45..50d77e98 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -30,11 +30,7 @@ class Header extends Base public function writeHeader(\PhpOffice\PhpWord\Section\Header $header) { // Create XML writer - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index a5f5084e..19ce58b0 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -26,12 +26,7 @@ class Rels extends WriterPart public function writeRelationships(PhpWord $phpWord = null) { // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } + $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index a24ac516..1c7c05e2 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -34,17 +34,11 @@ class Styles extends Base */ public function writeStyles(PhpWord $phpWord = null) { - // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter( - XMLWriter::STORAGE_DISK, - $this->getParentWriter()->getDiskCachingDirectory() - ); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } $this->phpWord = $phpWord; + + // Create XML writer + $xmlWriter = $this->getXmlWriter(); + // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('w:styles'); diff --git a/src/PhpWord/Writer/Word2007/WriterPart.php b/src/PhpWord/Writer/Word2007/WriterPart.php index 2d7860e0..ead47239 100755 --- a/src/PhpWord/Writer/Word2007/WriterPart.php +++ b/src/PhpWord/Writer/Word2007/WriterPart.php @@ -11,6 +11,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Exceptions\Exception; use PhpOffice\PhpWord\Writer\IWriter; +use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 writer part abstract class @@ -22,7 +23,7 @@ abstract class WriterPart * * @var IWriter */ - private $_parentWriter; + protected $parentWriter; /** * Set parent writer @@ -31,20 +32,41 @@ abstract class WriterPart */ public function setParentWriter(IWriter $pWriter = null) { - $this->_parentWriter = $pWriter; + $this->parentWriter = $pWriter; } /** * Get parent writer * * @return IWriter + * @throws Exception */ public function getParentWriter() { - if (!is_null($this->_parentWriter)) { - return $this->_parentWriter; + if (!is_null($this->parentWriter)) { + return $this->parentWriter; } else { throw new Exception("No parent IWriter assigned."); } } + + /** + * Get XML Writer + * + * @return XMLWriter + */ + protected function getXmlWriter() + { + $useDiskCaching = false; + if (!is_null($this->parentWriter)) { + if ($this->parentWriter->getUseDiskCaching()) { + $useDiskCaching = true; + } + } + if ($useDiskCaching) { + return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory()); + } else { + return new XMLWriter(XMLWriter::STORAGE_MEMORY); + } + } } diff --git a/src/PhpWord/Writer/Writer.php b/src/PhpWord/Writer/Writer.php new file mode 100644 index 00000000..eeba55ca --- /dev/null +++ b/src/PhpWord/Writer/Writer.php @@ -0,0 +1,184 @@ +phpWord)) { + return $this->phpWord; + } else { + throw new Exception("No PhpWord assigned."); + } + } + + /** + * Set PhpWord object + * + * @param PhpWord + * @return $this + */ + public function setPhpWord(PhpWord $phpWord = null) + { + $this->phpWord = $phpWord; + return $this; + } + + /** + * Get writer part + * + * @param string $pPartName Writer part name + * @return mixed + */ + public function getWriterPart($pPartName = '') + { + if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) { + return $this->writerParts[strtolower($pPartName)]; + } else { + return null; + } + } + + /** + * Get use disk caching status + * + * @return boolean + */ + public function getUseDiskCaching() + { + return $this->useDiskCaching; + } + + /** + * Set use disk caching status + * + * @param boolean $pValue + * @param string $pDirectory + * @return $this + */ + public function setUseDiskCaching($pValue = false, $pDirectory = null) + { + $this->useDiskCaching = $pValue; + + if (!is_null($pDirectory)) { + if (is_dir($pDirectory)) { + $this->diskCachingDirectory = $pDirectory; + } else { + throw new Exception("Directory does not exist: $pDirectory"); + } + } + + return $this; + } + + /** + * Get disk caching directory + * + * @return string + */ + public function getDiskCachingDirectory() + { + return $this->diskCachingDirectory; + } + + /** + * Get temporary file name + * + * If $pFilename is php://output or php://stdout, make it a temporary file + * + * @param string $pFilename + * @return string + */ + protected function getTempFile($pFilename) + { + $this->originalFilename = $pFilename; + if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { + $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_'); + if ($pFilename == '') { + $pFilename = $this->originalFilename; + } + } + $this->tempFilename = $pFilename; + + return $this->tempFilename; + } + + /** + * Cleanup temporary file + * + * If a temporary file was used, copy it to the correct file stream + */ + protected function cleanupTempFile() + { + if ($this->originalFilename != $this->tempFilename) { + if (copy($this->tempFilename, $this->originalFilename) === false) { + throw new Exception("Could not copy temporary zip file {$this->tempFilename} to {$this->originalFilename}."); + } + @unlink($this->tempFilename); + } + } +} From bf5eed4d26e6bde65e59987ff1efeccfb8bbbb9c Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Sun, 30 Mar 2014 05:27:25 -0700 Subject: [PATCH 027/146] List of authors has been updated in "composer.json". --- composer.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/composer.json b/composer.json index fcca56e7..6a2d9573 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,10 @@ { "name": "Ivan Lanin", "homepage": "http://ivan.lanin.org" + }, + { + "name": "Roman Syroeshko", + "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" } ], "require": { From acba6b448ab8a61eb5b4a74d2215bbd22df6876c Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 18:51:25 +0700 Subject: [PATCH 028/146] Refactoring & remove underscore prefix from method and property names --- src/PhpWord/DocumentProperties.php | 12 +- src/PhpWord/Section/CheckBox.php | 22 +- src/PhpWord/Section/Link.php | 8 +- src/PhpWord/Section/Text.php | 22 +- src/PhpWord/Section/TextBreak.php | 18 +- src/PhpWord/Section/TextRun.php | 9 +- src/PhpWord/Writer/ODText/Content.php | 22 +- src/PhpWord/Writer/ODText/Manifest.php | 4 +- src/PhpWord/Writer/RTF.php | 2 - src/PhpWord/Writer/Word2007.php | 16 +- src/PhpWord/Writer/Word2007/Base.php | 1473 +++++++++-------- src/PhpWord/Writer/Word2007/ContentTypes.php | 80 +- src/PhpWord/Writer/Word2007/Document.php | 154 +- src/PhpWord/Writer/Word2007/DocumentRels.php | 50 +- src/PhpWord/Writer/Word2007/Footer.php | 12 +- src/PhpWord/Writer/Word2007/Footnotes.php | 8 +- src/PhpWord/Writer/Word2007/FootnotesRels.php | 36 +- src/PhpWord/Writer/Word2007/Header.php | 14 +- src/PhpWord/Writer/Word2007/Rels.php | 41 +- src/PhpWord/Writer/Word2007/Styles.php | 27 +- 20 files changed, 934 insertions(+), 1096 deletions(-) diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 5e982646..63ff0275 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -39,14 +39,14 @@ class DocumentProperties /** * Created * - * @var datetime + * @var datetime|int */ private $_created; /** * Modified * - * @var datetime + * @var datetime|int */ private $_modified; @@ -102,7 +102,7 @@ class DocumentProperties /** * Custom Properties * - * @var string + * @var array */ private $_customProperties = array(); @@ -542,26 +542,21 @@ class DocumentProperties case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return self::PROPERTY_TYPE_INTEGER; - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return self::PROPERTY_TYPE_FLOAT; - break; case 'empty': // Empty case 'null': // Null case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return self::PROPERTY_TYPE_STRING; - break; case 'date': // Date and Time case 'filetime': // File Time return self::PROPERTY_TYPE_DATE; - break; case 'bool': // Boolean return self::PROPERTY_TYPE_BOOLEAN; - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -576,7 +571,6 @@ class DocumentProperties case 'clsid': // Class ID case 'cf': // Clipboard Data return self::PROPERTY_TYPE_UNKNOWN; - break; } return self::PROPERTY_TYPE_UNKNOWN; } diff --git a/src/PhpWord/Section/CheckBox.php b/src/PhpWord/Section/CheckBox.php index 00f75e54..5e101d9f 100644 --- a/src/PhpWord/Section/CheckBox.php +++ b/src/PhpWord/Section/CheckBox.php @@ -34,14 +34,14 @@ class CheckBox /** * Text style * - * @var Font + * @var string|Font */ private $fontStyle; /** * Paragraph style * - * @var Paragraph + * @var string|Paragraph */ private $paragraphStyle; @@ -50,8 +50,8 @@ class CheckBox * * @param string $name * @param string $text - * @param Font $fontStyle - * @param Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null) { @@ -66,9 +66,9 @@ class CheckBox /** * Set Text style * - * @param Font $style - * @param Paragraph $paragraphStyle - * @return Font + * @param mixed $style + * @param mixed $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -90,7 +90,7 @@ class CheckBox /** * Get Text style * - * @return Font + * @return string|Font */ public function getFontStyle() { @@ -100,8 +100,8 @@ class CheckBox /** * Set Paragraph style * - * @param Paragraph $style - * @return Paragraph + * @param mixed $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -121,7 +121,7 @@ class CheckBox /** * Get Paragraph style * - * @return Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/Link.php b/src/PhpWord/Section/Link.php index 39b1c56d..240d0445 100644 --- a/src/PhpWord/Section/Link.php +++ b/src/PhpWord/Section/Link.php @@ -41,14 +41,14 @@ class Link /** * Link style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $_styleFont; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ private $_styleParagraph; @@ -140,7 +140,7 @@ class Link /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -150,7 +150,7 @@ class Link /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/Text.php b/src/PhpWord/Section/Text.php index a99945fe..4e228cda 100644 --- a/src/PhpWord/Section/Text.php +++ b/src/PhpWord/Section/Text.php @@ -27,14 +27,14 @@ class Text /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $fontStyle; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ private $paragraphStyle; @@ -42,8 +42,8 @@ class Text * Create a new Text Element * * @param string $text - * @param null|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { @@ -55,9 +55,9 @@ class Text /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param string|array|Font $style + * @param string|array|Paragraph $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -79,7 +79,7 @@ class Text /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -89,8 +89,8 @@ class Text /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|Paragraph $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -110,7 +110,7 @@ class Text /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/TextBreak.php b/src/PhpWord/Section/TextBreak.php index 97f6deca..4df4c780 100755 --- a/src/PhpWord/Section/TextBreak.php +++ b/src/PhpWord/Section/TextBreak.php @@ -20,14 +20,14 @@ class TextBreak /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Pagaraph + * @var string|Paragraph */ private $paragraphStyle = null; /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $fontStyle = null; @@ -50,9 +50,9 @@ class TextBreak /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param mixed $style + * @param mixed $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -72,7 +72,7 @@ class TextBreak /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -82,8 +82,8 @@ class TextBreak /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|Paragraph $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -101,7 +101,7 @@ class TextBreak /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/TextRun.php b/src/PhpWord/Section/TextRun.php index 497f6f45..bcb5173a 100755 --- a/src/PhpWord/Section/TextRun.php +++ b/src/PhpWord/Section/TextRun.php @@ -12,6 +12,7 @@ namespace PhpOffice\PhpWord\Section; use PhpOffice\PhpWord\Exceptions\InvalidImageException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; /** @@ -22,7 +23,7 @@ class TextRun /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var Paragraph */ private $_styleParagraph; @@ -123,8 +124,8 @@ class TextRun * Add TextBreak * * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) { @@ -161,7 +162,7 @@ class TextRun /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 4e75068d..8142d9dc 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -244,11 +244,11 @@ class Content extends WriterPart foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter); + $this->writeTextBreak($xmlWriter); } elseif ($element instanceof Link) { $this->writeUnsupportedElement($xmlWriter, 'Link'); } elseif ($element instanceof Title) { @@ -271,9 +271,9 @@ class Content extends WriterPart } if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); + $this->writeEndSection($xmlWriter, $section); } else { - $this->_writeSection($xmlWriter, $section); + $this->writeSection($xmlWriter, $section); } } } @@ -292,7 +292,7 @@ class Content extends WriterPart * @param \PhpOffice\PhpWord\Section\Text $text * @param bool $withoutP */ - protected function _writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) + protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) { $styleFont = $text->getFontStyle(); $styleParagraph = $text->getParagraphStyle(); @@ -340,14 +340,14 @@ class Content extends WriterPart * @param \PhpOffice\PhpWord\Section\TextRun $textrun * @todo Enable all other section types */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) + protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) { $elements = $textrun->getElements(); $xmlWriter->startElement('text:p'); if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } } } @@ -359,7 +359,7 @@ class Content extends WriterPart * * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ - protected function _writeTextBreak(XMLWriter $xmlWriter = null) + protected function writeTextBreak(XMLWriter $xmlWriter = null) { $xmlWriter->startElement('text:p'); $xmlWriter->writeAttribute('text:style-name', 'Standard'); @@ -373,7 +373,7 @@ class Content extends WriterPart * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section $section */ - private function _writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) + private function writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) { } @@ -383,7 +383,7 @@ class Content extends WriterPart * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section $section */ - private function _writeSection(XMLWriter $xmlWriter = null, Section $section = null) + private function writeSection(XMLWriter $xmlWriter = null, Section $section = null) { } // @codeCoverageIgnoreEnd diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index cb92ddcc..25a17f2e 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -64,7 +64,7 @@ class Manifest extends WriterPart for ($i = 0; $i < $this->getParentWriter()->getDrawingHashTable()->count(); ++$i) { if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension()); - $mimeType = $this->_getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); + $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); $xmlWriter->startElement('manifest:file-entry'); $xmlWriter->writeAttribute('manifest:media-type', $mimeType); @@ -99,7 +99,7 @@ class Manifest extends WriterPart * @return string Mime Type * @throws \PhpOffice\PhpWord\Exceptions\Exception */ - private function _getImageMimeType($pFile = '') + private function getImageMimeType($pFile = '') { if (file_exists($pFile)) { $image = getimagesize($pFile); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index d7fc7101..cff6ca46 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -179,7 +179,6 @@ class RTF extends Writer implements IWriter // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { // PhpOffice\PhpWord\Style\Font @@ -232,7 +231,6 @@ class RTF extends Writer implements IWriter // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { // Font diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 6ceed4fb..cb5cfc72 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -34,14 +34,14 @@ class Word2007 extends Writer implements IWriter * * @var array */ - private $_imageTypes = array(); + private $imageTypes = array(); /** * Types of objects * * @var array */ - private $_objectTypes = array(); + private $objectTypes = array(); /** * Create new Word2007 writer @@ -167,8 +167,8 @@ class Word2007 extends Writer implements IWriter $objZip->addFromString( '[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes( - $this->_imageTypes, - $this->_objectTypes, + $this->imageTypes, + $this->objectTypes, $_cHdrs, $footers ) @@ -235,12 +235,12 @@ class Word2007 extends Writer implements IWriter if ($imageExtension === 'jpeg') { $imageExtension = 'jpg'; } - if (!in_array($imageType, $this->_imageTypes)) { - $this->_imageTypes[$imageExtension] = $imageType; + if (!in_array($imageType, $this->imageTypes)) { + $this->imageTypes[$imageExtension] = $imageType; } } else { - if (!in_array($extension, $this->_objectTypes)) { - $this->_objectTypes[] = $extension; + if (!in_array($extension, $this->objectTypes)) { + $this->objectTypes[] = $extension; } } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 644bf2a2..f813e586 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -10,23 +10,23 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\Footnote; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Link; use PhpOffice\PhpWord\Section\Title; +use PhpOffice\PhpWord\Section\Footer\PreserveText; +use PhpOffice\PhpWord\Section\TextBreak; +use PhpOffice\PhpWord\Section\ListItem; +use PhpOffice\PhpWord\Section\Table; +use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Section\Object; +use PhpOffice\PhpWord\Section\Footnote; use PhpOffice\PhpWord\Section\CheckBox; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style\Cell; -use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Cell; /** * Word2007 base part writer @@ -38,55 +38,33 @@ class Base extends WriterPart /** * Write text element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Text $text + * @param XMLWriter $xmlWriter + * @param Text $text * @param boolean $withoutP */ - protected function _writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) - { + protected function writeText( + XMLWriter $xmlWriter, + Text $text, + $withoutP = false + ) { $styleFont = $text->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $text->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - + $styleParagraph = $text->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $strText = htmlspecialchars($text->getText()); $strText = String::controlCharacterPHP2OOXML($strText); - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); } - + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $xmlWriter->writeAttribute('xml:space', 'preserve'); $xmlWriter->writeRaw($strText); $xmlWriter->endElement(); - $xmlWriter->endElement(); // w:r - if (!$withoutP) { $xmlWriter->endElement(); // w:p } @@ -95,57 +73,706 @@ class Base extends WriterPart /** * Write textrun element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param TextRun $textrun */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) - { + protected function writeTextRun( + XMLWriter $xmlWriter, + TextRun $textrun + ) { $elements = $textrun->getElements(); $styleParagraph = $textrun->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - $xmlWriter->startElement('w:p'); - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); + $this->writeLink($xmlWriter, $element, true); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element, true); + $this->writeImage($xmlWriter, $element, true); } elseif ($element instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $element, true); + $this->writeFootnote($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } } } + $xmlWriter->endElement(); // w:p + } + + /** + * Write link element + * + * @param XMLWriter $xmlWriter + * @param Link $link + * @param boolean $withoutP + */ + protected function writeLink( + XMLWriter $xmlWriter, + Link $link, + $withoutP = false + ) { + $rID = $link->getRelationId(); + $linkName = $link->getLinkName(); + if (is_null($linkName)) { + $linkName = $link->getLinkSrc(); + } + $styleFont = $link->getFontStyle(); + $sfIsObject = ($styleFont instanceof Font) ? true : false; + $styleParagraph = $link->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + } + $xmlWriter->startElement('w:hyperlink'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rID); + $xmlWriter->writeAttribute('w:history', '1'); + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $xmlWriter->writeRaw($linkName); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:hyperlink + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write title element + * + * @param XMLWriter $xmlWriter + * @param Title $title + */ + protected function writeTitle(XMLWriter $xmlWriter, Title $title) + { + $text = htmlspecialchars($title->getText()); + $text = String::controlCharacterPHP2OOXML($text); + $anchor = $title->getAnchor(); + $bookmarkId = $title->getBookmarkId(); + $style = $title->getStyle(); + + $xmlWriter->startElement('w:p'); + + if (!empty($style)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:pStyle'); + $xmlWriter->writeAttribute('w:val', $style); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:bookmarkStart'); + $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->writeAttribute('w:name', $anchor); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:bookmarkEnd'); + $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->endElement(); $xmlWriter->endElement(); } + /** + * Write preserve text element + * + * @param XMLWriter $xmlWriter + * @param TextRun $textrun + */ + protected function writePreserveText( + XMLWriter $xmlWriter, + PreserveText $textrun + ) { + $styleFont = $textrun->getFontStyle(); + $sfIsObject = ($styleFont instanceof Font) ? true : false; + $styleParagraph = $textrun->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + + $arrText = $textrun->getText(); + if (!is_array($arrText)) { + $arrText = array($arrText); + } + + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + foreach ($arrText as $text) { + if (substr($text, 0, 1) == '{') { + $text = substr($text, 1, -1); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } else { + $text = htmlspecialchars($text); + $text = String::controlCharacterPHP2OOXML($text); + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + + $xmlWriter->endElement(); // p + } + + /** + * Write text break element + * + * @param XMLWriter $xmlWriter + * @param TextBreak $element + */ + protected function writeTextBreak($xmlWriter, TextBreak $element = null) + { + $hasStyle = false; + if (!is_null($element)) { + $styleFont = $element->getFontStyle(); + $sfIsObject = ($styleFont instanceof Font) ? true : false; + $styleParagraph = $element->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + $hasStyle = !is_null($styleFont) || !is_null($styleParagraph); + } + if ($hasStyle) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + if (!is_null($styleFont)) { + $xmlWriter->startElement('w:pPr'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->endElement(); // w:pPr + } + $xmlWriter->endElement(); // w:p + } else { + // Null element. No paragraph nor font style + $xmlWriter->writeElement('w:p', null); + } + } + + /** + * Write list item element + * + * @param XMLWriter $xmlWriter + * @param ListItem $listItem + */ + protected function writeListItem(XMLWriter $xmlWriter, ListItem $listItem) + { + $textObject = $listItem->getTextObject(); + $text = $textObject->getText(); + $depth = $listItem->getDepth(); + $listType = $listItem->getStyle()->getListType(); + $styleParagraph = $textObject->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:pPr'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph, true); + $xmlWriter->startElement('w:numPr'); + $xmlWriter->startElement('w:ilvl'); + $xmlWriter->writeAttribute('w:val', $depth); + $xmlWriter->endElement(); // w:ilvl + $xmlWriter->startElement('w:numId'); + $xmlWriter->writeAttribute('w:val', $listType); + $xmlWriter->endElement(); // w:numId + $xmlWriter->endElement(); // w:numPr + $xmlWriter->endElement(); // w:pPr + $this->writeText($xmlWriter, $textObject, true); + $xmlWriter->endElement(); // w:p + } + + /** + * Write footnote reference element + * + * @param XMLWriter $xmlWriter + * @param Table $table + */ + protected function writeTable(XMLWriter $xmlWriter, Table $table) + { + $_rows = $table->getRows(); + $_cRows = count($_rows); + + if ($_cRows > 0) { + $xmlWriter->startElement('w:tbl'); + + // Table grid + $cellWidths = array(); + for ($i = 0; $i < $_cRows; $i++) { + $row = $_rows[$i]; + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); + } + } + $xmlWriter->startElement('w:tblGrid'); + foreach ($cellWidths as $width) { + $xmlWriter->startElement('w:gridCol'); + if (!is_null($width)) { + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + } + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); // w:tblGrid + + // Table style + $tblStyle = $table->getStyle(); + $tblWidth = $table->getWidth(); + if ($tblStyle instanceof \PhpOffice\PhpWord\Style\Table) { + $this->writeTableStyle($xmlWriter, $tblStyle, false); + } else { + if (!empty($tblStyle)) { + $xmlWriter->startElement('w:tblPr'); + $xmlWriter->startElement('w:tblStyle'); + $xmlWriter->writeAttribute('w:val', $tblStyle); + $xmlWriter->endElement(); + if (!is_null($tblWidth)) { + $xmlWriter->startElement('w:tblW'); + $xmlWriter->writeAttribute('w:w', $tblWidth); + $xmlWriter->writeAttribute('w:type', 'pct'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + } + + // Table rows + for ($i = 0; $i < $_cRows; $i++) { + $row = $_rows[$i]; + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $cantSplit = $rowStyle->getCantSplit(); + $exactHeight = $rowStyle->getExactHeight(); + + $xmlWriter->startElement('w:tr'); + + if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { + $xmlWriter->startElement('w:trPr'); + if (!is_null($height)) { + $xmlWriter->startElement('w:trHeight'); + $xmlWriter->writeAttribute('w:val', $height); + $xmlWriter->writeAttribute('w:hRule', ($exactHeight ? 'exact' : 'atLeast')); + $xmlWriter->endElement(); + } + if ($tblHeader) { + $xmlWriter->startElement('w:tblHeader'); + $xmlWriter->writeAttribute('w:val', '1'); + $xmlWriter->endElement(); + } + if ($cantSplit) { + $xmlWriter->startElement('w:cantSplit'); + $xmlWriter->writeAttribute('w:val', '1'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + + foreach ($row->getCells() as $cell) { + $xmlWriter->startElement('w:tc'); + + $cellStyle = $cell->getStyle(); + $width = $cell->getWidth(); + + $xmlWriter->startElement('w:tcPr'); + $xmlWriter->startElement('w:tcW'); + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + $xmlWriter->endElement(); + + if ($cellStyle instanceof Cell) { + $this->writeCellStyle($xmlWriter, $cellStyle); + } + + $xmlWriter->endElement(); + + $_elements = $cell->getElements(); + if (count($_elements) > 0) { + foreach ($_elements as $element) { + if ($element instanceof Text) { + $this->writeText($xmlWriter, $element); + } elseif ($element instanceof TextRun) { + $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof Link) { + $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof TextBreak) { + $this->writeTextBreak($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); + } elseif ($element instanceof Image) { + $this->writeImage($xmlWriter, $element); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element); + } elseif ($element instanceof PreserveText) { + $this->writePreserveText($xmlWriter, $element); + } elseif ($element instanceof CheckBox) { + $this->writeCheckBox($xmlWriter, $element); + } + } + } else { + $this->writeTextBreak($xmlWriter); + } + + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + } + + /** + * Write image element + * + * @param XMLWriter $xmlWriter + * @param Image $image + * @param boolean $withoutP + */ + protected function writeImage( + XMLWriter $xmlWriter, + Image $image, + $withoutP = false + ) { + $rId = $image->getRelationId(); + + $style = $image->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $align = $style->getAlign(); + $marginTop = $style->getMarginTop(); + $marginLeft = $style->getMarginLeft(); + $wrappingStyle = $style->getWrappingStyle(); + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + + if (!is_null($align)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:jc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + + $xmlWriter->startElement('w:r'); + + $xmlWriter->startElement('w:pict'); + + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + + $imgStyle = ''; + if (null !== $width) { + $imgStyle .= 'width:' . $width . 'px;'; + } + if (null !== $height) { + $imgStyle .= 'height:' . $height . 'px;'; + } + if (null !== $marginTop) { + $imgStyle .= 'margin-top:' . $marginTop . 'in;'; + } + if (null !== $marginLeft) { + $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; + } + + switch ($wrappingStyle) { + case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND: + $imgStyle .= 'position:absolute;z-index:-251658752;'; + break; + case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE: + $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + break; + case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_TIGHT: + $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; + break; + case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_INFRONT: + $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + break; + } + + $xmlWriter->writeAttribute('style', $imgStyle); + + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write watermark element + * + * @param XMLWriter $xmlWriter + * @param Image $image + */ + protected function writeWatermark(XMLWriter $xmlWriter, Image $image) + { + $rId = $image->getRelationId(); + + $style = $image->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $marginLeft = $style->getMarginLeft(); + $marginTop = $style->getMarginTop(); + + $xmlWriter->startElement('w:p'); + + $xmlWriter->startElement('w:r'); + + $xmlWriter->startElement('w:pict'); + + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + + $strStyle = 'position:absolute;'; + $strStyle .= ' width:' . $width . 'px;'; + $strStyle .= ' height:' . $height . 'px;'; + if (!is_null($marginTop)) { + $strStyle .= ' margin-top:' . $marginTop . 'px;'; + } + if (!is_null($marginLeft)) { + $strStyle .= ' margin-left:' . $marginLeft . 'px;'; + } + + $xmlWriter->writeAttribute('style', $strStyle); + + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + } + + /** + * Write object element + * + * @param XMLWriter $xmlWriter + * @param Object $object + */ + protected function writeObject(XMLWriter $xmlWriter, Object $object) + { + $rIdObject = $object->getRelationId(); + $rIdImage = $object->getImageRelationId(); + $shapeId = md5($rIdObject . '_' . $rIdImage); + $objectId = $object->getObjectId(); + $style = $object->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $align = $style->getAlign(); + + $xmlWriter->startElement('w:p'); + if (!is_null($align)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:jc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:object'); + $xmlWriter->writeAttribute('w:dxaOrig', '249'); + $xmlWriter->writeAttribute('w:dyaOrig', '160'); + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('id', $shapeId); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); + $xmlWriter->writeAttribute('o:ole', ''); + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); // v:imagedata + $xmlWriter->endElement(); // v:shape + $xmlWriter->startElement('o:OLEObject'); + $xmlWriter->writeAttribute('Type', 'Embed'); + $xmlWriter->writeAttribute('ProgID', 'Package'); + $xmlWriter->writeAttribute('ShapeID', $shapeId); + $xmlWriter->writeAttribute('DrawAspect', 'Icon'); + $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); + $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); + $xmlWriter->endElement(); // o:OLEObject + $xmlWriter->endElement(); // w:object + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p + } + + /** + * Write footnote element which links to the actual content in footnotes.xml + * + * @param XMLWriter $xmlWriter + * @param Footnote $footnote + * @param boolean $withoutP + */ + protected function writeFootnote( + XMLWriter $xmlWriter, + Footnote $footnote, + $withoutP = false + ) { + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr + $xmlWriter->startElement('w:footnoteReference'); + $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $xmlWriter->endElement(); // w:footnoteReference + $xmlWriter->endElement(); // w:r + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write CheckBox + * + * @param boolean $withoutP + * @param boolean $checkState + */ + protected function writeCheckBox( + XMLWriter $xmlWriter, + CheckBox $checkbox, + $withoutP = false, + $checkState = false + ) { + $name = htmlspecialchars($checkbox->getName()); + $name = String::controlCharacterPHP2OOXML($name); + $text = htmlspecialchars($checkbox->getText()); + $text = String::controlCharacterPHP2OOXML($text); + $styleFont = $checkbox->getFontStyle(); + $sfIsObject = ($styleFont instanceof Font) ? true : false; + $styleParagraph = $checkbox->getParagraphStyle(); + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->startElement('w:ffData'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', $name); + $xmlWriter->endElement(); //w:name + $xmlWriter->writeAttribute('w:enabled', ''); + $xmlWriter->startElement('w:calcOnExit'); + $xmlWriter->writeAttribute('w:val', '0'); + $xmlWriter->endElement(); //w:calcOnExit + $xmlWriter->startElement('w:checkBox'); + $xmlWriter->writeAttribute('w:sizeAuto', ''); + $xmlWriter->startElement('w:default'); + $xmlWriter->writeAttribute('w:val', ($checkState ? '1' : '0')); + $xmlWriter->endElement(); //w:default + $xmlWriter->endElement(); //w:checkBox + $xmlWriter->endElement(); // w:ffData + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw(' FORMCHECKBOX '); + $xmlWriter->endElement();// w:instrText + $xmlWriter->endElement(); // w:r + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'seperate'); + $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:r + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + /** * Write paragraph style * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param \PhpOffice\PhpWord\Style\Paragraph $style * @param bool $withoutPPR */ - protected function _writeParagraphStyle( + protected function writeParagraphStyle( XMLWriter $xmlWriter, - Paragraph $style, + Paragraph $style = null, $withoutPPR = false ) { @@ -239,174 +866,13 @@ class Base extends WriterPart } } - /** - * Write link element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Link $link - * @param boolean $withoutP - */ - protected function _writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) - { - $rID = $link->getRelationId(); - $linkName = $link->getLinkName(); - if (is_null($linkName)) { - $linkName = $link->getLinkSrc(); - } - - $styleFont = $link->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $link->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rID); - $xmlWriter->writeAttribute('w:history', '1'); - - $xmlWriter->startElement('w:r'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text - $xmlWriter->writeRaw($linkName); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write preserve text element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\TextRun $textrun - */ - protected function _writePreserveText(XMLWriter $xmlWriter, PreserveText $textrun) - { - $styleFont = $textrun->getFontStyle(); - $styleParagraph = $textrun->getParagraphStyle(); - - $sfIsObject = ($styleFont instanceof Font) ? true : false; - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $arrText = $textrun->getText(); - if (!is_array($arrText)) { - $arrText = array($arrText); - } - - $xmlWriter->startElement('w:p'); - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - foreach ($arrText as $text) { - - if (substr($text, 0, 1) == '{') { - $text = substr($text, 1, -1); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } else { - $text = htmlspecialchars($text); - $text = String::controlCharacterPHP2OOXML($text); - - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->endElement(); // p - } - /** * Write footnote reference element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section $section */ - protected function _writeTextStyle(XMLWriter $xmlWriter, Font $style) + protected function writeFontStyle(XMLWriter $xmlWriter, Font $style) { $font = $style->getName(); $bold = $style->getBold(); @@ -504,207 +970,14 @@ class Base extends WriterPart $xmlWriter->endElement(); } - /** - * Write text break element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextBreak $element - */ - protected function _writeTextBreak($xmlWriter, $element = null) - { - $hasStyle = false; - if (!is_null($element)) { - $fontStyle = $element->getFontStyle(); - $sfIsObject = ($fontStyle instanceof Font) ? true : false; - $paragraphStyle = $element->getParagraphStyle(); - $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; - $hasStyle = !is_null($fontStyle) || !is_null($paragraphStyle); - } - if ($hasStyle) { - // Paragraph style - $xmlWriter->startElement('w:p'); - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); - } elseif (!$spIsObject && !is_null($paragraphStyle)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $paragraphStyle); - $xmlWriter->endElement(); // w:pStyle - $xmlWriter->endElement(); // w:pPr - } - // Font style - if (!is_null($fontStyle)) { - $xmlWriter->startElement('w:pPr'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $fontStyle); - } elseif (!$sfIsObject && !is_null($fontStyle)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $fontStyle); - $xmlWriter->endElement(); // w:rStyle - $xmlWriter->endElement(); // w:rPr - } - $xmlWriter->endElement(); // w:pPr - } - $xmlWriter->endElement(); // w:p - } else { - // Null element. No paragraph nor font style - $xmlWriter->writeElement('w:p', null); - } - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Table $table - */ - protected function _writeTable(XMLWriter $xmlWriter, Table $table) - { - $_rows = $table->getRows(); - $_cRows = count($_rows); - - if ($_cRows > 0) { - $xmlWriter->startElement('w:tbl'); - - // Table grid - $cellWidths = array(); - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } - } - $xmlWriter->startElement('w:tblGrid'); - foreach ($cellWidths as $width) { - $xmlWriter->startElement('w:gridCol'); - if (!is_null($width)) { - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); // w:tblGrid - - // Table style - $tblStyle = $table->getStyle(); - $tblWidth = $table->getWidth(); - if ($tblStyle instanceof \PhpOffice\PhpWord\Style\Table) { - $this->_writeTableStyle($xmlWriter, $tblStyle, false); - } else { - if (!empty($tblStyle)) { - $xmlWriter->startElement('w:tblPr'); - $xmlWriter->startElement('w:tblStyle'); - $xmlWriter->writeAttribute('w:val', $tblStyle); - $xmlWriter->endElement(); - if (!is_null($tblWidth)) { - $xmlWriter->startElement('w:tblW'); - $xmlWriter->writeAttribute('w:w', $tblWidth); - $xmlWriter->writeAttribute('w:type', 'pct'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - - // Table rows - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; - $height = $row->getHeight(); - $rowStyle = $row->getStyle(); - $tblHeader = $rowStyle->getTblHeader(); - $cantSplit = $rowStyle->getCantSplit(); - $exactHeight = $rowStyle->getExactHeight(); - - $xmlWriter->startElement('w:tr'); - - if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { - $xmlWriter->startElement('w:trPr'); - if (!is_null($height)) { - $xmlWriter->startElement('w:trHeight'); - $xmlWriter->writeAttribute('w:val', $height); - $xmlWriter->writeAttribute('w:hRule', ($exactHeight ? 'exact' : 'atLeast')); - $xmlWriter->endElement(); - } - if ($tblHeader) { - $xmlWriter->startElement('w:tblHeader'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($cantSplit) { - $xmlWriter->startElement('w:cantSplit'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('w:tc'); - - $cellStyle = $cell->getStyle(); - $width = $cell->getWidth(); - - $xmlWriter->startElement('w:tcPr'); - $xmlWriter->startElement('w:tcW'); - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - - if ($cellStyle instanceof Cell) { - $this->_writeCellStyle($xmlWriter, $cellStyle); - } - - $xmlWriter->endElement(); - - $_elements = $cell->getElements(); - if (count($_elements) > 0) { - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); - } elseif ($element instanceof CheckBox) { - $this->_writeCheckBox($xmlWriter, $element); - } - } - } else { - $this->_writeTextBreak($xmlWriter); - } - - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - /** * Write table style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Style\Table $style * @param boolean $isFullStyle */ - protected function _writeTableStyle( + protected function writeTableStyle( XMLWriter $xmlWriter, \PhpOffice\PhpWord\Style\Table $style, $isFullStyle = true @@ -822,7 +1095,7 @@ class Base extends WriterPart // First Row $firstRow = $style->getFirstRow(); if (!is_null($firstRow)) { - $this->_writeRowStyle($xmlWriter, 'firstRow', $firstRow); + $this->writeRowStyle($xmlWriter, 'firstRow', $firstRow); } } } @@ -830,11 +1103,11 @@ class Base extends WriterPart /** * Write row style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $type * @param PhpOffice\PhpWord\Style\Table $style */ - protected function _writeRowStyle( + protected function writeRowStyle( XMLWriter $xmlWriter, $type, \PhpOffice\PhpWord\Style\Table $style @@ -900,10 +1173,10 @@ class Base extends WriterPart /** * Write footnote reference element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Style\Cell $style */ - protected function _writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) + protected function writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) { $bgColor = $style->getBgColor(); $valign = $style->getVAlign(); @@ -1007,288 +1280,85 @@ class Base extends WriterPart } /** - * Write image element + * Write individual rels entry * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image - * @param boolean $withoutP + * @param XMLWriter $xmlWriter + * @param int $pId Relationship ID + * @param string $pType Relationship type + * @param string $pTarget Relationship target + * @param string $pTargetMode Relationship target mode */ - protected function _writeImage(XMLWriter $xmlWriter, $image, $withoutP = false) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - $marginTop = $style->getMarginTop(); - $marginLeft = $style->getMarginLeft(); - $wrappingStyle = $style->getWrappingStyle(); - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + protected function writeRelationship( + XMLWriter $xmlWriter = null, + $pId = 1, + $pType = '', + $pTarget = '', + $pTargetMode = '' + ) { + if ($pType != '' && $pTarget != '') { + if (strpos($pId, 'rId') === false) { + $pId = 'rId' . $pId; } - } - $xmlWriter->startElement('w:r'); + // Write relationship + $xmlWriter->startElement('Relationship'); + $xmlWriter->writeAttribute('Id', $pId); + $xmlWriter->writeAttribute('Type', $pType); + $xmlWriter->writeAttribute('Target', $pTarget); - $xmlWriter->startElement('w:pict'); + if ($pTargetMode != '') { + $xmlWriter->writeAttribute('TargetMode', $pTargetMode); + } - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $imgStyle = ''; - if (null !== $width) { - $imgStyle .= 'width:' . $width . 'px;'; - } - if (null !== $height) { - $imgStyle .= 'height:' . $height . 'px;'; - } - if (null !== $marginTop) { - $imgStyle .= 'margin-top:' . $marginTop . 'in;'; - } - if (null !== $marginLeft) { - $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; - } - - switch ($wrappingStyle) { - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND: - $imgStyle .= 'position:absolute;z-index:-251658752;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE: - $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_TIGHT: - $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_INFRONT: - $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - } - - $xmlWriter->writeAttribute('style', $imgStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p + $xmlWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); } } /** - * Write footnote reference element + * Write inline paragraph style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image + * @param XMLWriter $xmlWriter + * @param Paragraph|string $styleParagraph + * @param boolean $spIsObject + * @param boolean $withoutPPR */ - protected function _writeWatermark(XMLWriter $xmlWriter, $image) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $marginLeft = $style->getMarginLeft(); - $marginTop = $style->getMarginTop(); - - $xmlWriter->startElement('w:p'); - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:pict'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $strStyle = 'position:absolute;'; - $strStyle .= ' width:' . $width . 'px;'; - $strStyle .= ' height:' . $height . 'px;'; - if (!is_null($marginTop)) { - $strStyle .= ' margin-top:' . $marginTop . 'px;'; - } - if (!is_null($marginLeft)) { - $strStyle .= ' margin-left:' . $marginLeft . 'px;'; - } - - $xmlWriter->writeAttribute('style', $strStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write title element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Title $title - */ - protected function _writeTitle(XMLWriter $xmlWriter, Title $title) - { - $text = htmlspecialchars($title->getText()); - $text = String::controlCharacterPHP2OOXML($text); - $anchor = $title->getAnchor(); - $bookmarkId = $title->getBookmarkId(); - $style = $title->getStyle(); - - $xmlWriter->startElement('w:p'); - - if (!empty($style)) { - $xmlWriter->startElement('w:pPr'); + private function writeInlineParagraphStyle( + XMLWriter $xmlWriter, + $styleParagraph = null, + $withoutPPR = false + ) { + $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; + if ($spIsObject) { + $this->writeParagraphStyle($xmlWriter, $styleParagraph, $withoutPPR); + } elseif (!$spIsObject && !is_null($styleParagraph)) { + if (!$withoutPPR) { + $xmlWriter->startElement('w:pPr'); + } $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $style); + $xmlWriter->writeAttribute('w:val', $styleParagraph); $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->writeAttribute('w:name', $anchor); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write footnote element which links to the actual content in footnotes.xml - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote - * @param boolean $withoutP - */ - protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) - { - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); - $xmlWriter->endElement(); // w:rStyle - $xmlWriter->endElement(); // w:rPr - $xmlWriter->startElement('w:footnoteReference'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); - $xmlWriter->endElement(); // w:footnoteReference - - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write CheckBox - * - * @param boolean $withoutP - * @param boolean $checkState - */ - protected function _writeCheckBox(XMLWriter $xmlWriter, CheckBox $checkbox, $withoutP = false, $checkState = false) - { - $name = htmlspecialchars($checkbox->getName()); - $name = String::controlCharacterPHP2OOXML($name); - $text = htmlspecialchars($checkbox->getText()); - $text = String::controlCharacterPHP2OOXML($text); - - $styleFont = $checkbox->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - $styleParagraph = $checkbox->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); + if (!$withoutPPR) { $xmlWriter->endElement(); } } + } - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->startElement('w:ffData'); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $name); - $xmlWriter->endElement(); //w:name - $xmlWriter->writeAttribute('w:enabled', ''); - $xmlWriter->startElement('w:calcOnExit'); - $xmlWriter->writeAttribute('w:val', '0'); - $xmlWriter->endElement(); //w:calcOnExit - $xmlWriter->startElement('w:checkBox'); - $xmlWriter->writeAttribute('w:sizeAuto', ''); - $xmlWriter->startElement('w:default'); - $xmlWriter->writeAttribute('w:val', ($checkState ? '1' : '0')); - $xmlWriter->endElement(); //w:default - $xmlWriter->endElement(); //w:checkBox - $xmlWriter->endElement(); // w:ffData - $xmlWriter->endElement(); // w:fldChar - $xmlWriter->endElement(); // w:r - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw(' FORMCHECKBOX '); - $xmlWriter->endElement();// w:instrText - $xmlWriter->endElement(); // w:r - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'seperate'); - $xmlWriter->endElement();// w:fldChar - $xmlWriter->endElement(); // w:r - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement();// w:fldChar - $xmlWriter->endElement(); // w:r - - $xmlWriter->startElement('w:r'); + /** + * Write inline font style + * + * @param XMLWriter $xmlWriter + * @param Font|string $styleFont + * @param boolean $sfIsObject + */ + private function writeInlineFontStyle( + XMLWriter $xmlWriter, + $styleFont = null + ) { + $sfIsObject = ($styleFont instanceof Font) ? true : false; if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); + $this->writeFontStyle($xmlWriter, $styleFont); } elseif (!$sfIsObject && !is_null($styleFont)) { $xmlWriter->startElement('w:rPr'); $xmlWriter->startElement('w:rStyle'); @@ -1296,14 +1366,5 @@ class Base extends WriterPart $xmlWriter->endElement(); $xmlWriter->endElement(); } - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); // w:t - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } } } diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 9f8c3fb2..2e2f3def 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -19,12 +19,12 @@ class ContentTypes extends WriterPart { /** * Write [Content_Types].xml - * @param array $_imageTypes - * @param array $_objectTypes + * @param array $imageTypes + * @param array $objectTypes * @param int $_cHdrs * @param array $footers */ - public function writeContentTypes($_imageTypes, $_objectTypes, $_cHdrs, $footers) + public function writeContentTypes($imageTypes, $objectTypes, $_cHdrs, $footers) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -37,27 +37,27 @@ class ContentTypes extends WriterPart $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); // Rels - $this->_writeDefaultContentType( + $this->writeDefaultContentType( $xmlWriter, 'rels', 'application/vnd.openxmlformats-package.relationships+xml' ); // XML - $this->_writeDefaultContentType( + $this->writeDefaultContentType( $xmlWriter, 'xml', 'application/xml' ); // Add media content-types - foreach ($_imageTypes as $key => $value) { - $this->_writeDefaultContentType($xmlWriter, $key, $value); + foreach ($imageTypes as $key => $value) { + $this->writeDefaultContentType($xmlWriter, $key, $value); } // Add embedding content-types - if (count($_objectTypes) > 0) { - $this->_writeDefaultContentType( + if (count($objectTypes) > 0) { + $this->writeDefaultContentType( $xmlWriter, 'bin', 'application/vnd.openxmlformats-officedocument.oleObject' @@ -65,76 +65,76 @@ class ContentTypes extends WriterPart } // DocProps - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/docProps/app.xml', 'application/vnd.openxmlformats-officedocument.extended-properties+xml' ); - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml' ); // Document - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/document.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' ); // Styles - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/styles.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml' ); // Numbering - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/numbering.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml' ); // Settings - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/settings.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml' ); // Theme1 - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/theme/theme1.xml', 'application/vnd.openxmlformats-officedocument.theme+xml' ); // WebSettings - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/webSettings.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml' ); // Font Table - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/fontTable.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml' ); // Footnotes - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/footnotes.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml' ); for ($i = 1; $i <= $_cHdrs; $i++) { - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/header' . $i . '.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml' @@ -143,7 +143,7 @@ class ContentTypes extends WriterPart for ($i = 1; $i <= count($footers); $i++) { if (!is_null($footers[$i])) { - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/footer' . $i . '.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml' @@ -158,23 +158,6 @@ class ContentTypes extends WriterPart return $xmlWriter->getData(); } - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _getImageMimeType($pFile = '') - { - if (file_exists($pFile)) { - $image = getimagesize($pFile); - return image_type_to_mime_type($image[2]); - } else { - throw new Exception("File $pFile does not exist"); - } - } - /** * Write Default XML element * @@ -183,7 +166,7 @@ class ContentTypes extends WriterPart * @param string $pContentType Content type * @throws \PhpOffice\PhpWord\Exceptions\Exception */ - private function _writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type @@ -204,7 +187,7 @@ class ContentTypes extends WriterPart * @param string $pContentType Content type * @throws \PhpOffice\PhpWord\Exceptions\Exception */ - private function _writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type @@ -216,4 +199,21 @@ class ContentTypes extends WriterPart throw new Exception("Invalid parameters passed."); } } + + /** + * Get image mime type + * + * @param string $pFile Filename + * @return string Mime Type + * @throws \PhpOffice\PhpWord\Exceptions\Exception + */ + private function getImageMimeType($pFile = '') + { + if (file_exists($pFile)) { + $image = getimagesize($pFile); + return image_type_to_mime_type($image[2]); + } else { + throw new Exception("File $pFile does not exist"); + } + } } diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 585050df..05fd145a 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -72,38 +72,38 @@ class Document extends Base $_elements = $section->getElements(); foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); + $this->writeLink($xmlWriter, $element); } elseif ($element instanceof Title) { - $this->_writeTitle($xmlWriter, $element); + $this->writeTitle($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof PageBreak) { - $this->_writePageBreak($xmlWriter); + $this->writePageBreak($xmlWriter); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); + $this->writeListItem($xmlWriter, $element); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); + $this->writeObject($xmlWriter, $element); } elseif ($element instanceof TOC) { - $this->_writeTOC($xmlWriter); + $this->writeTOC($xmlWriter); } elseif ($element instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $element); + $this->writeFootnote($xmlWriter, $element); } elseif ($element instanceof CheckBox) { - $this->_writeCheckBox($xmlWriter, $element); + $this->writeCheckBox($xmlWriter, $element); } } if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); + $this->writeEndSection($xmlWriter, $section); } else { - $this->_writeSection($xmlWriter, $section); + $this->writeSection($xmlWriter, $section); } } } @@ -121,11 +121,11 @@ class Document extends Base * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section $section */ - private function _writeSection(XMLWriter $xmlWriter, Section $section) + private function writeSection(XMLWriter $xmlWriter, Section $section) { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:pPr'); - $this->_writeEndSection($xmlWriter, $section, 3); + $this->writeEndSection($xmlWriter, $section, 3); $xmlWriter->endElement(); $xmlWriter->endElement(); } @@ -136,7 +136,7 @@ class Document extends Base * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section $section */ - private function _writeEndSection(XMLWriter $xmlWriter, Section $section) + private function writeEndSection(XMLWriter $xmlWriter, Section $section) { $settings = $section->getSettings(); $_headers = $section->getHeaders(); @@ -274,7 +274,7 @@ class Document extends Base * * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ - private function _writePageBreak(XMLWriter $xmlWriter) + private function writePageBreak(XMLWriter $xmlWriter) { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); @@ -285,122 +285,12 @@ class Document extends Base $xmlWriter->endElement(); } - /** - * Write list item element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\ListItem $listItem - */ - public function _writeListItem(XMLWriter $xmlWriter, ListItem $listItem) - { - $textObject = $listItem->getTextObject(); - $text = $textObject->getText(); - $styleParagraph = $textObject->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $depth = $listItem->getDepth(); - $listType = $listItem->getStyle()->getListType(); - - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:pPr'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph, true); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:numPr'); - - $xmlWriter->startElement('w:ilvl'); - $xmlWriter->writeAttribute('w:val', $depth); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $listType); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $this->_writeText($xmlWriter, $textObject, true); - - $xmlWriter->endElement(); - } - - /** - * Write object element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Object $object - */ - protected function _writeObject(XMLWriter $xmlWriter, Object $object) - { - $rIdObject = $object->getRelationId(); - $rIdImage = $object->getImageRelationId(); - $shapeId = md5($rIdObject . '_' . $rIdImage); - - $objectId = $object->getObjectId(); - - $style = $object->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - - - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:object'); - $xmlWriter->writeAttribute('w:dxaOrig', '249'); - $xmlWriter->writeAttribute('w:dyaOrig', '160'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('id', $shapeId); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); - $xmlWriter->writeAttribute('o:ole', ''); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->startElement('o:OLEObject'); - $xmlWriter->writeAttribute('Type', 'Embed'); - $xmlWriter->writeAttribute('ProgID', 'Package'); - $xmlWriter->writeAttribute('ShapeID', $shapeId); - $xmlWriter->writeAttribute('DrawAspect', 'Icon'); - $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:r - - $xmlWriter->endElement(); // w:p - } - /** * Write TOC element * * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter */ - private function _writeTOC(XMLWriter $xmlWriter) + private function writeTOC(XMLWriter $xmlWriter) { $titles = TOC::getTitles(); $styleFont = TOC::getStyleFont(); @@ -421,7 +311,7 @@ class Document extends Base $xmlWriter->startElement('w:pPr'); if ($isObject && !is_null($styleFont->getParagraphStyle())) { - $this->_writeParagraphStyle($xmlWriter, $styleFont->getParagraphStyle()); + $this->writeParagraphStyle($xmlWriter, $styleFont->getParagraphStyle()); } if ($indent > 0) { @@ -479,7 +369,7 @@ class Document extends Base $xmlWriter->startElement('w:r'); if ($isObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); + $this->writeFontStyle($xmlWriter, $styleFont); } $xmlWriter->startElement('w:t'); diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 20a014f2..53a5ded5 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 document rels part writer */ -class DocumentRels extends WriterPart +class DocumentRels extends Base { /** * Write word/_rels/document.xml.rels @@ -35,7 +35,7 @@ class DocumentRels extends WriterPart $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Relationship word/document.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', @@ -43,7 +43,7 @@ class DocumentRels extends WriterPart ); // Relationship word/numbering.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 2, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering', @@ -51,7 +51,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 3, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings', @@ -59,7 +59,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 4, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', @@ -67,7 +67,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 5, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings', @@ -75,7 +75,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 6, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable', @@ -89,7 +89,7 @@ class DocumentRels extends WriterPart $relationId = $relation['rID']; $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, @@ -128,7 +128,7 @@ class DocumentRels extends WriterPart $relationName = $relation['target']; $relationId = $relation['rID']; - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, @@ -142,36 +142,4 @@ class DocumentRels extends WriterPart // Return return $xmlWriter->getData(); } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index d4f68826..49fad838 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -50,17 +50,17 @@ class Footer extends Base foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); + $this->writePreserveText($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index d69e0f0c..1d244b01 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -80,7 +80,7 @@ class Footnotes extends Base * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param PhpOffice\PhpWord\Section\Footnote $footnote */ - private function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) + protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) { $xmlWriter->startElement('w:footnote'); $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); @@ -89,7 +89,7 @@ class Footnotes extends Base $paragraphStyle = $footnote->getParagraphStyle(); $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); + $this->writeParagraphStyle($xmlWriter, $paragraphStyle); } elseif (!$spIsObject && !is_null($paragraphStyle)) { $xmlWriter->startElement('w:pPr'); $xmlWriter->startElement('w:pStyle'); @@ -118,9 +118,9 @@ class Footnotes extends Base if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); + $this->writeLink($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index f9e5c015..d0665de3 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 footnotes rel part writer */ -class FootnotesRels extends WriterPart +class FootnotesRels extends Base { /** * Write word/_rels/footnotes.xml.rels @@ -41,7 +41,7 @@ class FootnotesRels extends WriterPart $relationId = $relation['rID']; $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - $this->_writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); + $this->writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); } $xmlWriter->endElement(); @@ -49,36 +49,4 @@ class FootnotesRels extends WriterPart // Return return $xmlWriter->getData(); } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 50d77e98..88400c50 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -51,21 +51,21 @@ class Header extends Base foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { if (!$element->getIsWatermark()) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } else { - $this->_writeWatermark($xmlWriter, $element); + $this->writeWatermark($xmlWriter, $element); } } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); + $this->writePreserveText($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index 19ce58b0..e7e26856 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 rels part writer */ -class Rels extends WriterPart +class Rels extends Base { /** * Write _rels/.rels @@ -38,7 +38,7 @@ class Rels extends WriterPart $relationId = 1; // Relationship word/document.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', @@ -46,7 +46,7 @@ class Rels extends WriterPart ); // Relationship docProps/core.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', @@ -54,7 +54,7 @@ class Rels extends WriterPart ); // Relationship docProps/app.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', @@ -65,37 +65,4 @@ class Rels extends WriterPart return $xmlWriter->getData(); } - - /** - * Write Override content type - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID. rId will be prepended! - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index 1c7c05e2..ca0acfdb 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -20,13 +20,6 @@ use PhpOffice\PhpWord\Style\Paragraph; */ class Styles extends Base { - /** - * PhpWord object - * - * @var PhpWord - */ - private $phpWord; - /** * Write word/styles.xml * @@ -34,8 +27,6 @@ class Styles extends Base */ public function writeStyles(PhpWord $phpWord = null) { - $this->phpWord = $phpWord; - // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -52,7 +43,7 @@ class Styles extends Base ); // Write default styles $styles = Style::getStyles(); - $this->writeDefaultStyles($xmlWriter, $styles); + $this->writeDefaultStyles($xmlWriter, $phpWord, $styles); // Write other styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { @@ -94,10 +85,10 @@ class Styles extends Base $xmlWriter->startElement('w:basedOn'); $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); + $this->writeParagraphStyle($xmlWriter, $paragraphStyle); } - $this->_writeTextStyle($xmlWriter, $style); + $this->writeFontStyle($xmlWriter, $style); $xmlWriter->endElement(); @@ -127,7 +118,7 @@ class Styles extends Base $xmlWriter->endElement(); } - $this->_writeParagraphStyle($xmlWriter, $style); + $this->writeParagraphStyle($xmlWriter, $style); $xmlWriter->endElement(); } elseif ($style instanceof \PhpOffice\PhpWord\Style\Table) { @@ -144,7 +135,7 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', '99'); $xmlWriter->endElement(); - $this->_writeTableStyle($xmlWriter, $style); + $this->writeTableStyle($xmlWriter, $style); $xmlWriter->endElement(); // w:style } @@ -163,10 +154,10 @@ class Styles extends Base * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter * @param array $styles */ - private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) + private function writeDefaultStyles(XMLWriter $xmlWriter, PhpWord $phpWord, $styles) { - $fontName = $this->phpWord->getDefaultFontName(); - $fontSize = $this->phpWord->getDefaultFontSize(); + $fontName = $phpWord->getDefaultFontName(); + $fontSize = $phpWord->getDefaultFontSize(); // Default font $xmlWriter->startElement('w:docDefaults'); @@ -197,7 +188,7 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); // w:name if (array_key_exists('Normal', $styles)) { - $this->_writeParagraphStyle($xmlWriter, $styles['Normal']); + $this->writeParagraphStyle($xmlWriter, $styles['Normal']); } $xmlWriter->endElement(); // w:style From 41407825a2d998baabb2024ac65d8cbc202de223 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 22:23:12 +0700 Subject: [PATCH 029/146] Namespace adjustments on writer classes --- src/PhpWord/Writer/ODText.php | 8 ++--- src/PhpWord/Writer/ODText/Content.php | 26 +++++++------- src/PhpWord/Writer/ODText/Manifest.php | 4 +-- src/PhpWord/Writer/ODText/Meta.php | 2 +- src/PhpWord/Writer/ODText/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Styles.php | 10 +++--- src/PhpWord/Writer/RTF.php | 10 +++--- src/PhpWord/Writer/Word2007.php | 2 +- src/PhpWord/Writer/Word2007/Base.php | 36 ++++++++++---------- src/PhpWord/Writer/Word2007/ContentTypes.php | 10 +++--- src/PhpWord/Writer/Word2007/DocProps.php | 2 +- src/PhpWord/Writer/Word2007/Document.php | 14 ++++---- src/PhpWord/Writer/Word2007/Footer.php | 5 +-- src/PhpWord/Writer/Word2007/Footnotes.php | 20 ++++------- src/PhpWord/Writer/Word2007/Header.php | 5 +-- src/PhpWord/Writer/Word2007/Rels.php | 2 +- src/PhpWord/Writer/Word2007/Styles.php | 7 ++-- src/PhpWord/Writer/Writer.php | 2 +- 18 files changed, 81 insertions(+), 86 deletions(-) diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 8c58df60..3aebf2a4 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -26,13 +26,13 @@ class ODText extends Writer implements IWriter /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * - * @var \PhpOffice\PhpWord\HashTable + * @var HashTable */ private $drawingHashTable; /** * Create new ODText writer - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) { @@ -57,7 +57,7 @@ class ODText extends Writer implements IWriter * Save PhpWord to file * * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ public function save($pFilename = null) { @@ -139,7 +139,7 @@ class ODText extends Writer implements IWriter /** * Get PHPWord_Worksheet_BaseDrawing HashTable * - * @return \PhpOffice\PhpWord\HashTable + * @return HashTable */ public function getDrawingHashTable() { diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 8142d9dc..2e9a61e6 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -35,7 +35,7 @@ class Content extends WriterPart /** * Write content file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeContent(PhpWord $phpWord = null) @@ -126,7 +126,7 @@ class Content extends WriterPart $numFonts = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $numFonts++; $name = $style->getName(); @@ -158,7 +158,7 @@ class Content extends WriterPart if (preg_match('#^T[0-9]+$#', $styleName) != 0 || preg_match('#^P[0-9]+$#', $styleName) != 0 ) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $styleName); @@ -288,8 +288,8 @@ class Content extends WriterPart /** * Write text * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\Text $text + * @param XMLWriter $xmlWriter + * @param Text $text * @param bool $withoutP */ protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) @@ -336,8 +336,8 @@ class Content extends WriterPart /** * Write TextRun section * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextRun $textrun + * @param XMLWriter $xmlWriter + * @param TextRun $textrun * @todo Enable all other section types */ protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) @@ -357,7 +357,7 @@ class Content extends WriterPart /** * Write TextBreak * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ protected function writeTextBreak(XMLWriter $xmlWriter = null) { @@ -370,8 +370,8 @@ class Content extends WriterPart /** * Write end section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ private function writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) { @@ -380,8 +380,8 @@ class Content extends WriterPart /** * Write section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ private function writeSection(XMLWriter $xmlWriter = null, Section $section = null) { @@ -391,7 +391,7 @@ class Content extends WriterPart /** * Write unsupported element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $element */ private function writeUnsupportedElement($xmlWriter, $element) diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 25a17f2e..31168e3d 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -21,7 +21,7 @@ class Manifest extends WriterPart /** * Write Manifest file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeManifest(PhpWord $phpWord = null) @@ -97,7 +97,7 @@ class Manifest extends WriterPart * * @param string $pFile Filename * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ private function getImageMimeType($pFile = '') { diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index fdd0ec7c..51647173 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -20,7 +20,7 @@ class Meta extends WriterPart /** * Write Meta file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeMeta(PhpWord $phpWord = null) diff --git a/src/PhpWord/Writer/ODText/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php index 0d4e598e..1e713f2c 100644 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Mimetype.php @@ -19,7 +19,7 @@ class Mimetype extends WriterPart /** * Write Mimetype to Text format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string Text Output */ public function writeMimetype(PhpWord $phpWord = null) diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 6a91a7e2..4ae937e0 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -24,7 +24,7 @@ class Styles extends WriterPart /** * Write Styles file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeStyles(PhpWord $phpWord = null) @@ -73,7 +73,7 @@ class Styles extends WriterPart $numFonts = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $numFonts++; $name = $style->getName(); @@ -144,7 +144,7 @@ class Styles extends WriterPart if (preg_match('#^T[0-9]+$#', $styleName) == 0 && preg_match('#^P[0-9]+$#', $styleName) == 0 ) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { // style:style $xmlWriter->startElement('style:style'); @@ -168,7 +168,7 @@ class Styles extends WriterPart $xmlWriter->endElement(); $xmlWriter->endElement(); } elseif ($style instanceof Paragraph) { - // PhpOffice\PhpWord\Style\Paragraph + // Paragraph // style:style $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $styleName); @@ -183,7 +183,7 @@ class Styles extends WriterPart $xmlWriter->endElement(); } elseif ($style instanceof Table) { - // PhpOffice\PhpWord\Style\Table + // Table } } } diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index cff6ca46..e37e53b3 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -36,7 +36,7 @@ class RTF extends Writer implements IWriter /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * - * @var \PhpOffice\PhpWord\HashTable + * @var HashTable */ private $drawingHashTable; @@ -63,7 +63,7 @@ class RTF extends Writer implements IWriter /** * Create new RTF writer - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) { @@ -78,7 +78,7 @@ class RTF extends Writer implements IWriter * Save PhpWord to file * * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ public function save($pFilename = null) { @@ -98,7 +98,7 @@ class RTF extends Writer implements IWriter /** * Get PHPWord_Worksheet_BaseDrawing HashTable * - * @return \PhpOffice\PhpWord\HashTable + * @return HashTable */ public function getDrawingHashTable() { @@ -181,7 +181,7 @@ class RTF extends Writer implements IWriter $styles = Style::getStyles(); if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { if (in_array($style->getName(), $arrFonts) == false) { $arrFonts[] = $style->getName(); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index cb5cfc72..4c55006f 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -46,7 +46,7 @@ class Word2007 extends Writer implements IWriter /** * Create new Word2007 writer * - * @param PhpOffice\PhpWord\PhpWord + * @param PhpWord */ public function __construct(PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index f813e586..2a1e01f5 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -27,6 +27,8 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Cell; +use PhpOffice\PhpWord\Style\Table as TableStyle; +use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Word2007 base part writer @@ -197,7 +199,7 @@ class Base extends WriterPart * Write preserve text element * * @param XMLWriter $xmlWriter - * @param TextRun $textrun + * @param PreserveText $textrun */ protected function writePreserveText( XMLWriter $xmlWriter, @@ -364,7 +366,7 @@ class Base extends WriterPart // Table style $tblStyle = $table->getStyle(); $tblWidth = $table->getWidth(); - if ($tblStyle instanceof \PhpOffice\PhpWord\Style\Table) { + if ($tblStyle instanceof TableStyle) { $this->writeTableStyle($xmlWriter, $tblStyle, false); } else { if (!empty($tblStyle)) { @@ -523,16 +525,16 @@ class Base extends WriterPart } switch ($wrappingStyle) { - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND: + case ImageStyle::WRAPPING_STYLE_BEHIND: $imgStyle .= 'position:absolute;z-index:-251658752;'; break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE: + case ImageStyle::WRAPPING_STYLE_SQUARE: $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_TIGHT: + case ImageStyle::WRAPPING_STYLE_TIGHT: $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_INFRONT: + case ImageStyle::WRAPPING_STYLE_INFRONT: $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; break; } @@ -767,7 +769,7 @@ class Base extends WriterPart * Write paragraph style * * @param XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Style\Paragraph $style + * @param Paragraph $style * @param bool $withoutPPR */ protected function writeParagraphStyle( @@ -867,10 +869,10 @@ class Base extends WriterPart } /** - * Write footnote reference element + * Write font style * * @param XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param Font $style */ protected function writeFontStyle(XMLWriter $xmlWriter, Font $style) { @@ -974,12 +976,12 @@ class Base extends WriterPart * Write table style * * @param XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Table $style + * @param TableStyle $style * @param boolean $isFullStyle */ protected function writeTableStyle( XMLWriter $xmlWriter, - \PhpOffice\PhpWord\Style\Table $style, + TableStyle $style, $isFullStyle = true ) { $bgColor = $style->getBgColor(); @@ -1105,12 +1107,12 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param string $type - * @param PhpOffice\PhpWord\Style\Table $style + * @param TableStyle $style */ protected function writeRowStyle( XMLWriter $xmlWriter, $type, - \PhpOffice\PhpWord\Style\Table $style + TableStyle $style ) { $brdSz = $style->getBorderSize(); $brdCol = $style->getBorderColor(); @@ -1174,7 +1176,7 @@ class Base extends WriterPart * Write footnote reference element * * @param XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Cell $style + * @param Cell $style */ protected function writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) { @@ -1321,10 +1323,9 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param Paragraph|string $styleParagraph - * @param boolean $spIsObject * @param boolean $withoutPPR */ - private function writeInlineParagraphStyle( + protected function writeInlineParagraphStyle( XMLWriter $xmlWriter, $styleParagraph = null, $withoutPPR = false @@ -1350,9 +1351,8 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param Font|string $styleFont - * @param boolean $sfIsObject */ - private function writeInlineFontStyle( + protected function writeInlineFontStyle( XMLWriter $xmlWriter, $styleFont = null ) { diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 2e2f3def..65c75384 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -161,10 +161,10 @@ class ContentTypes extends WriterPart /** * Write Default XML element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer + * @param XMLWriter $xmlWriter XML Writer * @param string $pPartname Part name * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ private function writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { @@ -182,10 +182,10 @@ class ContentTypes extends WriterPart /** * Write Override XML element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $pPartname Part name * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ private function writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { @@ -205,7 +205,7 @@ class ContentTypes extends WriterPart * * @param string $pFile Filename * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ private function getImageMimeType($pFile = '') { diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 591dfc0e..92c2fab8 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -110,7 +110,7 @@ class DocProps extends WriterPart /** * Write docProps/core.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeDocPropsCore(PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 05fd145a..03184bd1 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -36,7 +36,7 @@ class Document extends Base /** * Write word/document.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeDocument(PhpWord $phpWord = null) { @@ -118,8 +118,8 @@ class Document extends Base /** * Write begin section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ private function writeSection(XMLWriter $xmlWriter, Section $section) { @@ -133,8 +133,8 @@ class Document extends Base /** * Write end section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ private function writeEndSection(XMLWriter $xmlWriter, Section $section) { @@ -272,7 +272,7 @@ class Document extends Base /** * Write page break element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ private function writePageBreak(XMLWriter $xmlWriter) { @@ -288,7 +288,7 @@ class Document extends Base /** * Write TOC element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ private function writeTOC(XMLWriter $xmlWriter) { diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index 49fad838..4a3b97f6 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -15,6 +15,7 @@ use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Footer as FooterElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -25,9 +26,9 @@ class Footer extends Base /** * Write word/footnotes.xml * - * @param PhpOffice\PhpWord\Section\Footer $footer + * @param FooterElement $footer */ - public function writeFooter(\PhpOffice\PhpWord\Section\Footer $footer) + public function writeFooter(FooterElement $footer) { // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 1d244b01..ce4aba60 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -77,26 +77,18 @@ class Footnotes extends Base /** * Write footnote content, overrides method in parent class * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote + * @param XMLWriter $xmlWriter + * @param Footnote $footnote + * @param boolean $withoutP */ - protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) + protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) { $xmlWriter->startElement('w:footnote'); $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); $xmlWriter->startElement('w:p'); // Paragraph style - $paragraphStyle = $footnote->getParagraphStyle(); - $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; - if ($spIsObject) { - $this->writeParagraphStyle($xmlWriter, $paragraphStyle); - } elseif (!$spIsObject && !is_null($paragraphStyle)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $paragraphStyle); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } + $styleParagraph = $footnote->getParagraphStyle(); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); // Reference symbol $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:rPr'); diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 88400c50..03757693 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -15,6 +15,7 @@ use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Header as HeaderElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -25,9 +26,9 @@ class Header extends Base /** * Write word/headerx.xml * - * @param PhpOffice\PhpWord\Section\Header $header + * @param HeaderElement $header */ - public function writeHeader(\PhpOffice\PhpWord\Section\Header $header) + public function writeHeader(HeaderElement $header) { // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index e7e26856..3e41033f 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -21,7 +21,7 @@ class Rels extends Base /** * Write _rels/.rels * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeRelationships(PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index ca0acfdb..c7b35faf 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -14,6 +14,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Table; /** * Word2007 styles part writer @@ -23,7 +24,7 @@ class Styles extends Base /** * Write word/styles.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeStyles(PhpWord $phpWord = null) { @@ -121,7 +122,7 @@ class Styles extends Base $this->writeParagraphStyle($xmlWriter, $style); $xmlWriter->endElement(); - } elseif ($style instanceof \PhpOffice\PhpWord\Style\Table) { + } elseif ($style instanceof Table) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'table'); $xmlWriter->writeAttribute('w:customStyle', '1'); @@ -151,7 +152,7 @@ class Styles extends Base /** * Write default font and other default styles * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param array $styles */ private function writeDefaultStyles(XMLWriter $xmlWriter, PhpWord $phpWord, $styles) diff --git a/src/PhpWord/Writer/Writer.php b/src/PhpWord/Writer/Writer.php index eeba55ca..bc749738 100644 --- a/src/PhpWord/Writer/Writer.php +++ b/src/PhpWord/Writer/Writer.php @@ -22,7 +22,7 @@ abstract class Writer implements IWriter /** * PHPWord object * - * @var PhpOffice\PhpWord\PhpWord + * @var PhpWord */ protected $phpWord = null; From f911f5ccbe26feef737b37cdbe52911e5078e9de Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 22:53:47 +0700 Subject: [PATCH 030/146] Namespace alias --- src/PhpWord/TOC.php | 11 ++--- src/PhpWord/Writer/Word2007/Base.php | 62 +++++++++++----------------- 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index e6a24234..bd1c3f38 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -10,6 +10,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\TOC as TOCStyle; /** * Table of contents @@ -26,14 +27,14 @@ class TOC /** * TOC style * - * @var PhpOffice\PhpWord\Style\TOC + * @var TOCStyle */ private static $_styleTOC; /** * Font style * - * @var PhpOffice\PhpWord\Style\Font|array|string + * @var Font|array|string */ private static $_styleFont; @@ -60,7 +61,7 @@ class TOC */ public function __construct($styleFont = null, $styleTOC = null) { - self::$_styleTOC = new \PhpOffice\PhpWord\Style\TOC(); + self::$_styleTOC = new TOCStyle(); if (!is_null($styleTOC) && is_array($styleTOC)) { foreach ($styleTOC as $key => $value) { @@ -122,7 +123,7 @@ class TOC /** * Get TOC Style * - * @return \PhpOffice\PhpWord\Style\TOC + * @return TOCStyle */ public static function getStyleTOC() { @@ -132,7 +133,7 @@ class TOC /** * Get Font Style * - * @return \PhpOffice\PhpWord\Style\Font + * @return Font */ public static function getStyleFont() { diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 2a1e01f5..3acf6c1d 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -50,9 +50,7 @@ class Base extends WriterPart $withoutP = false ) { $styleFont = $text->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; $styleParagraph = $text->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $strText = htmlspecialchars($text->getText()); $strText = String::controlCharacterPHP2OOXML($strText); @@ -84,7 +82,6 @@ class Base extends WriterPart ) { $elements = $textrun->getElements(); $styleParagraph = $textrun->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $xmlWriter->startElement('w:p'); $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); if (count($elements) > 0) { @@ -123,9 +120,7 @@ class Base extends WriterPart $linkName = $link->getLinkSrc(); } $styleFont = $link->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; $styleParagraph = $link->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; if (!$withoutP) { $xmlWriter->startElement('w:p'); @@ -206,9 +201,7 @@ class Base extends WriterPart PreserveText $textrun ) { $styleFont = $textrun->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; $styleParagraph = $textrun->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $arrText = $textrun->getText(); if (!is_array($arrText)) { @@ -272,11 +265,11 @@ class Base extends WriterPart protected function writeTextBreak($xmlWriter, TextBreak $element = null) { $hasStyle = false; + $styleFont = null; + $styleParagraph = null; if (!is_null($element)) { $styleFont = $element->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; $styleParagraph = $element->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $hasStyle = !is_null($styleFont) || !is_null($styleParagraph); } if ($hasStyle) { @@ -303,11 +296,9 @@ class Base extends WriterPart protected function writeListItem(XMLWriter $xmlWriter, ListItem $listItem) { $textObject = $listItem->getTextObject(); - $text = $textObject->getText(); $depth = $listItem->getDepth(); $listType = $listItem->getStyle()->getListType(); $styleParagraph = $textObject->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:pPr'); @@ -619,8 +610,6 @@ class Base extends WriterPart $shapeId = md5($rIdObject . '_' . $rIdImage); $objectId = $object->getObjectId(); $style = $object->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); $align = $style->getAlign(); $xmlWriter->startElement('w:p'); @@ -705,9 +694,7 @@ class Base extends WriterPart $text = htmlspecialchars($checkbox->getText()); $text = String::controlCharacterPHP2OOXML($text); $styleFont = $checkbox->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; $styleParagraph = $checkbox->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; if (!$withoutP) { $xmlWriter->startElement('w:p'); @@ -774,7 +761,7 @@ class Base extends WriterPart */ protected function writeParagraphStyle( XMLWriter $xmlWriter, - Paragraph $style = null, + Paragraph $style, $withoutPPR = false ) { @@ -1122,7 +1109,6 @@ class Base extends WriterPart $bLeft = (!is_null($brdSz[1])) ? true : false; $bRight = (!is_null($brdSz[2])) ? true : false; $bBottom = (!is_null($brdSz[3])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom) ? true : false; $xmlWriter->startElement('w:tblStylePr'); $xmlWriter->writeAttribute('w:type', $type); @@ -1178,7 +1164,7 @@ class Base extends WriterPart * @param XMLWriter $xmlWriter * @param Cell $style */ - protected function writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) + protected function writeCellStyle(XMLWriter $xmlWriter, Cell $style) { $bgColor = $style->getBgColor(); $valign = $style->getVAlign(); @@ -1291,7 +1277,7 @@ class Base extends WriterPart * @param string $pTargetMode Relationship target mode */ protected function writeRelationship( - XMLWriter $xmlWriter = null, + XMLWriter $xmlWriter, $pId = 1, $pType = '', $pTarget = '', @@ -1330,18 +1316,19 @@ class Base extends WriterPart $styleParagraph = null, $withoutPPR = false ) { - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - if ($spIsObject) { + if ($styleParagraph instanceof Paragraph) { $this->writeParagraphStyle($xmlWriter, $styleParagraph, $withoutPPR); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - if (!$withoutPPR) { - $xmlWriter->startElement('w:pPr'); - } - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - if (!$withoutPPR) { + } else { + if (!is_null($styleParagraph)) { + if (!$withoutPPR) { + $xmlWriter->startElement('w:pPr'); + } + $xmlWriter->startElement('w:pStyle'); + $xmlWriter->writeAttribute('w:val', $styleParagraph); $xmlWriter->endElement(); + if (!$withoutPPR) { + $xmlWriter->endElement(); + } } } } @@ -1356,15 +1343,16 @@ class Base extends WriterPart XMLWriter $xmlWriter, $styleFont = null ) { - $sfIsObject = ($styleFont instanceof Font) ? true : false; - if ($sfIsObject) { + if ($styleFont instanceof Font) { $this->writeFontStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + } else { + if (!is_null($styleFont)) { + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', $styleFont); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } } } } From 99c25c3abcfcc16bc909d6694ec96031d8bbeddb Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 23:04:48 +0700 Subject: [PATCH 031/146] Namespace updates --- src/PhpWord/Section/Footer/PreserveText.php | 12 ++++++------ src/PhpWord/Style/Font.php | 4 ++-- src/PhpWord/Style/Row.php | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/PhpWord/Section/Footer/PreserveText.php b/src/PhpWord/Section/Footer/PreserveText.php index 579ca271..fbeb16be 100644 --- a/src/PhpWord/Section/Footer/PreserveText.php +++ b/src/PhpWord/Section/Footer/PreserveText.php @@ -27,16 +27,16 @@ class PreserveText /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $_styleFont; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var Paragraph */ - private $_styleParagraph; + private string|$_styleParagraph; /** @@ -45,7 +45,7 @@ class PreserveText * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return PHPWord_Section_Footer_PreserveText + * @return $this */ public function __construct($text = null, $styleFont = null, $styleParagraph = null) { @@ -88,7 +88,7 @@ class PreserveText /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -98,7 +98,7 @@ class PreserveText /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 3d235343..d1f5353a 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -479,8 +479,8 @@ class Font /** * Set background color * - * @param string $pValue - * @return PHPWord_Style_Font + * @param string $pValue + * @return $this */ public function setBgColor($pValue = null) { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 74b4d966..2b714024 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -57,7 +57,7 @@ class Row * Set tblHeader * * @param boolean $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setTblHeader($pValue = false) { @@ -82,7 +82,7 @@ class Row * Set cantSplit * * @param boolean $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setCantSplit($pValue = false) { @@ -107,7 +107,7 @@ class Row * Set exactHeight * * @param bool $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setExactHeight($pValue = false) { From 45b0baf7bce599571780b2f9bda21fd32879f442 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 30 Mar 2014 18:51:25 +0700 Subject: [PATCH 032/146] Refactor writer classes --- composer.json | 4 + src/PhpWord/DocumentProperties.php | 12 +- src/PhpWord/Section/CheckBox.php | 22 +- src/PhpWord/Section/Footer/PreserveText.php | 10 +- src/PhpWord/Section/Link.php | 8 +- src/PhpWord/Section/Text.php | 22 +- src/PhpWord/Section/TextBreak.php | 18 +- src/PhpWord/Section/TextRun.php | 9 +- src/PhpWord/Style/Font.php | 4 +- src/PhpWord/Style/Row.php | 6 +- src/PhpWord/TOC.php | 11 +- src/PhpWord/Writer/ODText.php | 8 +- src/PhpWord/Writer/ODText/Content.php | 48 +- src/PhpWord/Writer/ODText/Manifest.php | 8 +- src/PhpWord/Writer/ODText/Meta.php | 2 +- src/PhpWord/Writer/ODText/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Styles.php | 10 +- src/PhpWord/Writer/RTF.php | 12 +- src/PhpWord/Writer/Word2007.php | 18 +- src/PhpWord/Writer/Word2007/Base.php | 1495 +++++++++-------- src/PhpWord/Writer/Word2007/ContentTypes.php | 88 +- src/PhpWord/Writer/Word2007/DocProps.php | 2 +- src/PhpWord/Writer/Word2007/Document.php | 168 +- src/PhpWord/Writer/Word2007/DocumentRels.php | 50 +- src/PhpWord/Writer/Word2007/Footer.php | 17 +- src/PhpWord/Writer/Word2007/Footnotes.php | 24 +- src/PhpWord/Writer/Word2007/FootnotesRels.php | 36 +- src/PhpWord/Writer/Word2007/Header.php | 19 +- src/PhpWord/Writer/Word2007/Rels.php | 43 +- src/PhpWord/Writer/Word2007/Styles.php | 34 +- src/PhpWord/Writer/Writer.php | 2 +- 31 files changed, 1019 insertions(+), 1193 deletions(-) diff --git a/composer.json b/composer.json index fcca56e7..6a2d9573 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,10 @@ { "name": "Ivan Lanin", "homepage": "http://ivan.lanin.org" + }, + { + "name": "Roman Syroeshko", + "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" } ], "require": { diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 5e982646..63ff0275 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -39,14 +39,14 @@ class DocumentProperties /** * Created * - * @var datetime + * @var datetime|int */ private $_created; /** * Modified * - * @var datetime + * @var datetime|int */ private $_modified; @@ -102,7 +102,7 @@ class DocumentProperties /** * Custom Properties * - * @var string + * @var array */ private $_customProperties = array(); @@ -542,26 +542,21 @@ class DocumentProperties case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return self::PROPERTY_TYPE_INTEGER; - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return self::PROPERTY_TYPE_FLOAT; - break; case 'empty': // Empty case 'null': // Null case 'lpstr': // LPSTR case 'lpwstr': // LPWSTR case 'bstr': // Basic String return self::PROPERTY_TYPE_STRING; - break; case 'date': // Date and Time case 'filetime': // File Time return self::PROPERTY_TYPE_DATE; - break; case 'bool': // Boolean return self::PROPERTY_TYPE_BOOLEAN; - break; case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -576,7 +571,6 @@ class DocumentProperties case 'clsid': // Class ID case 'cf': // Clipboard Data return self::PROPERTY_TYPE_UNKNOWN; - break; } return self::PROPERTY_TYPE_UNKNOWN; } diff --git a/src/PhpWord/Section/CheckBox.php b/src/PhpWord/Section/CheckBox.php index 00f75e54..5e101d9f 100644 --- a/src/PhpWord/Section/CheckBox.php +++ b/src/PhpWord/Section/CheckBox.php @@ -34,14 +34,14 @@ class CheckBox /** * Text style * - * @var Font + * @var string|Font */ private $fontStyle; /** * Paragraph style * - * @var Paragraph + * @var string|Paragraph */ private $paragraphStyle; @@ -50,8 +50,8 @@ class CheckBox * * @param string $name * @param string $text - * @param Font $fontStyle - * @param Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function __construct($name = null, $text = null, $fontStyle = null, $paragraphStyle = null) { @@ -66,9 +66,9 @@ class CheckBox /** * Set Text style * - * @param Font $style - * @param Paragraph $paragraphStyle - * @return Font + * @param mixed $style + * @param mixed $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -90,7 +90,7 @@ class CheckBox /** * Get Text style * - * @return Font + * @return string|Font */ public function getFontStyle() { @@ -100,8 +100,8 @@ class CheckBox /** * Set Paragraph style * - * @param Paragraph $style - * @return Paragraph + * @param mixed $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -121,7 +121,7 @@ class CheckBox /** * Get Paragraph style * - * @return Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/Footer/PreserveText.php b/src/PhpWord/Section/Footer/PreserveText.php index 579ca271..6fbd7bba 100644 --- a/src/PhpWord/Section/Footer/PreserveText.php +++ b/src/PhpWord/Section/Footer/PreserveText.php @@ -27,14 +27,14 @@ class PreserveText /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $_styleFont; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ private $_styleParagraph; @@ -45,7 +45,7 @@ class PreserveText * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return PHPWord_Section_Footer_PreserveText + * @return $this */ public function __construct($text = null, $styleFont = null, $styleParagraph = null) { @@ -88,7 +88,7 @@ class PreserveText /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -98,7 +98,7 @@ class PreserveText /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/Link.php b/src/PhpWord/Section/Link.php index 39b1c56d..240d0445 100644 --- a/src/PhpWord/Section/Link.php +++ b/src/PhpWord/Section/Link.php @@ -41,14 +41,14 @@ class Link /** * Link style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $_styleFont; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ private $_styleParagraph; @@ -140,7 +140,7 @@ class Link /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -150,7 +150,7 @@ class Link /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/Text.php b/src/PhpWord/Section/Text.php index a99945fe..4e228cda 100644 --- a/src/PhpWord/Section/Text.php +++ b/src/PhpWord/Section/Text.php @@ -27,14 +27,14 @@ class Text /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $fontStyle; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ private $paragraphStyle; @@ -42,8 +42,8 @@ class Text * Create a new Text Element * * @param string $text - * @param null|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { @@ -55,9 +55,9 @@ class Text /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param string|array|Font $style + * @param string|array|Paragraph $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -79,7 +79,7 @@ class Text /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -89,8 +89,8 @@ class Text /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|Paragraph $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -110,7 +110,7 @@ class Text /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/TextBreak.php b/src/PhpWord/Section/TextBreak.php index 97f6deca..4df4c780 100755 --- a/src/PhpWord/Section/TextBreak.php +++ b/src/PhpWord/Section/TextBreak.php @@ -20,14 +20,14 @@ class TextBreak /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Pagaraph + * @var string|Paragraph */ private $paragraphStyle = null; /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|Font */ private $fontStyle = null; @@ -50,9 +50,9 @@ class TextBreak /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param mixed $style + * @param mixed $paragraphStyle + * @return string|Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -72,7 +72,7 @@ class TextBreak /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|Font */ public function getFontStyle() { @@ -82,8 +82,8 @@ class TextBreak /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|Paragraph $style + * @return string|Paragraph */ public function setParagraphStyle($style = null) { @@ -101,7 +101,7 @@ class TextBreak /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Section/TextRun.php b/src/PhpWord/Section/TextRun.php index 497f6f45..bcb5173a 100755 --- a/src/PhpWord/Section/TextRun.php +++ b/src/PhpWord/Section/TextRun.php @@ -12,6 +12,7 @@ namespace PhpOffice\PhpWord\Section; use PhpOffice\PhpWord\Exceptions\InvalidImageException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; /** @@ -22,7 +23,7 @@ class TextRun /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var Paragraph */ private $_styleParagraph; @@ -123,8 +124,8 @@ class TextRun * Add TextBreak * * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) { @@ -161,7 +162,7 @@ class TextRun /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 3d235343..d1f5353a 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -479,8 +479,8 @@ class Font /** * Set background color * - * @param string $pValue - * @return PHPWord_Style_Font + * @param string $pValue + * @return $this */ public function setBgColor($pValue = null) { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 74b4d966..2b714024 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -57,7 +57,7 @@ class Row * Set tblHeader * * @param boolean $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setTblHeader($pValue = false) { @@ -82,7 +82,7 @@ class Row * Set cantSplit * * @param boolean $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setCantSplit($pValue = false) { @@ -107,7 +107,7 @@ class Row * Set exactHeight * * @param bool $pValue - * @return PHPWord_Style_Row + * @return $this */ public function setExactHeight($pValue = false) { diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index e6a24234..bd1c3f38 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -10,6 +10,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\TOC as TOCStyle; /** * Table of contents @@ -26,14 +27,14 @@ class TOC /** * TOC style * - * @var PhpOffice\PhpWord\Style\TOC + * @var TOCStyle */ private static $_styleTOC; /** * Font style * - * @var PhpOffice\PhpWord\Style\Font|array|string + * @var Font|array|string */ private static $_styleFont; @@ -60,7 +61,7 @@ class TOC */ public function __construct($styleFont = null, $styleTOC = null) { - self::$_styleTOC = new \PhpOffice\PhpWord\Style\TOC(); + self::$_styleTOC = new TOCStyle(); if (!is_null($styleTOC) && is_array($styleTOC)) { foreach ($styleTOC as $key => $value) { @@ -122,7 +123,7 @@ class TOC /** * Get TOC Style * - * @return \PhpOffice\PhpWord\Style\TOC + * @return TOCStyle */ public static function getStyleTOC() { @@ -132,7 +133,7 @@ class TOC /** * Get Font Style * - * @return \PhpOffice\PhpWord\Style\Font + * @return Font */ public static function getStyleFont() { diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 8c58df60..3aebf2a4 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -26,13 +26,13 @@ class ODText extends Writer implements IWriter /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * - * @var \PhpOffice\PhpWord\HashTable + * @var HashTable */ private $drawingHashTable; /** * Create new ODText writer - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) { @@ -57,7 +57,7 @@ class ODText extends Writer implements IWriter * Save PhpWord to file * * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ public function save($pFilename = null) { @@ -139,7 +139,7 @@ class ODText extends Writer implements IWriter /** * Get PHPWord_Worksheet_BaseDrawing HashTable * - * @return \PhpOffice\PhpWord\HashTable + * @return HashTable */ public function getDrawingHashTable() { diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 4e75068d..2e9a61e6 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -35,7 +35,7 @@ class Content extends WriterPart /** * Write content file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeContent(PhpWord $phpWord = null) @@ -126,7 +126,7 @@ class Content extends WriterPart $numFonts = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $numFonts++; $name = $style->getName(); @@ -158,7 +158,7 @@ class Content extends WriterPart if (preg_match('#^T[0-9]+$#', $styleName) != 0 || preg_match('#^P[0-9]+$#', $styleName) != 0 ) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $styleName); @@ -244,11 +244,11 @@ class Content extends WriterPart foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter); + $this->writeTextBreak($xmlWriter); } elseif ($element instanceof Link) { $this->writeUnsupportedElement($xmlWriter, 'Link'); } elseif ($element instanceof Title) { @@ -271,9 +271,9 @@ class Content extends WriterPart } if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); + $this->writeEndSection($xmlWriter, $section); } else { - $this->_writeSection($xmlWriter, $section); + $this->writeSection($xmlWriter, $section); } } } @@ -288,11 +288,11 @@ class Content extends WriterPart /** * Write text * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\Text $text + * @param XMLWriter $xmlWriter + * @param Text $text * @param bool $withoutP */ - protected function _writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) + protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) { $styleFont = $text->getFontStyle(); $styleParagraph = $text->getParagraphStyle(); @@ -336,18 +336,18 @@ class Content extends WriterPart /** * Write TextRun section * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextRun $textrun + * @param XMLWriter $xmlWriter + * @param TextRun $textrun * @todo Enable all other section types */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) + protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) { $elements = $textrun->getElements(); $xmlWriter->startElement('text:p'); if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } } } @@ -357,9 +357,9 @@ class Content extends WriterPart /** * Write TextBreak * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ - protected function _writeTextBreak(XMLWriter $xmlWriter = null) + protected function writeTextBreak(XMLWriter $xmlWriter = null) { $xmlWriter->startElement('text:p'); $xmlWriter->writeAttribute('text:style-name', 'Standard'); @@ -370,20 +370,20 @@ class Content extends WriterPart /** * Write end section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ - private function _writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) + private function writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) { } /** * Write section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ - private function _writeSection(XMLWriter $xmlWriter = null, Section $section = null) + private function writeSection(XMLWriter $xmlWriter = null, Section $section = null) { } // @codeCoverageIgnoreEnd @@ -391,7 +391,7 @@ class Content extends WriterPart /** * Write unsupported element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $element */ private function writeUnsupportedElement($xmlWriter, $element) diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index cb92ddcc..31168e3d 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -21,7 +21,7 @@ class Manifest extends WriterPart /** * Write Manifest file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeManifest(PhpWord $phpWord = null) @@ -64,7 +64,7 @@ class Manifest extends WriterPart for ($i = 0; $i < $this->getParentWriter()->getDrawingHashTable()->count(); ++$i) { if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension()); - $mimeType = $this->_getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); + $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); $xmlWriter->startElement('manifest:file-entry'); $xmlWriter->writeAttribute('manifest:media-type', $mimeType); @@ -97,9 +97,9 @@ class Manifest extends WriterPart * * @param string $pFile Filename * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ - private function _getImageMimeType($pFile = '') + private function getImageMimeType($pFile = '') { if (file_exists($pFile)) { $image = getimagesize($pFile); diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index fdd0ec7c..51647173 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -20,7 +20,7 @@ class Meta extends WriterPart /** * Write Meta file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeMeta(PhpWord $phpWord = null) diff --git a/src/PhpWord/Writer/ODText/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php index 0d4e598e..1e713f2c 100644 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Mimetype.php @@ -19,7 +19,7 @@ class Mimetype extends WriterPart /** * Write Mimetype to Text format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string Text Output */ public function writeMimetype(PhpWord $phpWord = null) diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 6a91a7e2..4ae937e0 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -24,7 +24,7 @@ class Styles extends WriterPart /** * Write Styles file to XML format * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @return string XML Output */ public function writeStyles(PhpWord $phpWord = null) @@ -73,7 +73,7 @@ class Styles extends WriterPart $numFonts = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { $numFonts++; $name = $style->getName(); @@ -144,7 +144,7 @@ class Styles extends WriterPart if (preg_match('#^T[0-9]+$#', $styleName) == 0 && preg_match('#^P[0-9]+$#', $styleName) == 0 ) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { // style:style $xmlWriter->startElement('style:style'); @@ -168,7 +168,7 @@ class Styles extends WriterPart $xmlWriter->endElement(); $xmlWriter->endElement(); } elseif ($style instanceof Paragraph) { - // PhpOffice\PhpWord\Style\Paragraph + // Paragraph // style:style $xmlWriter->startElement('style:style'); $xmlWriter->writeAttribute('style:name', $styleName); @@ -183,7 +183,7 @@ class Styles extends WriterPart $xmlWriter->endElement(); } elseif ($style instanceof Table) { - // PhpOffice\PhpWord\Style\Table + // Table } } } diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index d7fc7101..e37e53b3 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -36,7 +36,7 @@ class RTF extends Writer implements IWriter /** * Private unique PHPWord_Worksheet_BaseDrawing HashTable * - * @var \PhpOffice\PhpWord\HashTable + * @var HashTable */ private $drawingHashTable; @@ -63,7 +63,7 @@ class RTF extends Writer implements IWriter /** * Create new RTF writer - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) { @@ -78,7 +78,7 @@ class RTF extends Writer implements IWriter * Save PhpWord to file * * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ public function save($pFilename = null) { @@ -98,7 +98,7 @@ class RTF extends Writer implements IWriter /** * Get PHPWord_Worksheet_BaseDrawing HashTable * - * @return \PhpOffice\PhpWord\HashTable + * @return HashTable */ public function getDrawingHashTable() { @@ -179,10 +179,9 @@ class RTF extends Writer implements IWriter // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + // Font if ($style instanceof Font) { if (in_array($style->getName(), $arrFonts) == false) { $arrFonts[] = $style->getName(); @@ -232,7 +231,6 @@ class RTF extends Writer implements IWriter // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { foreach ($styles as $styleName => $style) { // Font diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 6ceed4fb..4c55006f 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -34,19 +34,19 @@ class Word2007 extends Writer implements IWriter * * @var array */ - private $_imageTypes = array(); + private $imageTypes = array(); /** * Types of objects * * @var array */ - private $_objectTypes = array(); + private $objectTypes = array(); /** * Create new Word2007 writer * - * @param PhpOffice\PhpWord\PhpWord + * @param PhpWord */ public function __construct(PhpWord $phpWord = null) { @@ -167,8 +167,8 @@ class Word2007 extends Writer implements IWriter $objZip->addFromString( '[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes( - $this->_imageTypes, - $this->_objectTypes, + $this->imageTypes, + $this->objectTypes, $_cHdrs, $footers ) @@ -235,12 +235,12 @@ class Word2007 extends Writer implements IWriter if ($imageExtension === 'jpeg') { $imageExtension = 'jpg'; } - if (!in_array($imageType, $this->_imageTypes)) { - $this->_imageTypes[$imageExtension] = $imageType; + if (!in_array($imageType, $this->imageTypes)) { + $this->imageTypes[$imageExtension] = $imageType; } } else { - if (!in_array($extension, $this->_objectTypes)) { - $this->_objectTypes[] = $extension; + if (!in_array($extension, $this->objectTypes)) { + $this->objectTypes[] = $extension; } } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 644bf2a2..3acf6c1d 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -10,23 +10,25 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\Footnote; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Link; use PhpOffice\PhpWord\Section\Title; +use PhpOffice\PhpWord\Section\Footer\PreserveText; +use PhpOffice\PhpWord\Section\TextBreak; +use PhpOffice\PhpWord\Section\ListItem; +use PhpOffice\PhpWord\Section\Table; +use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Section\Object; +use PhpOffice\PhpWord\Section\Footnote; use PhpOffice\PhpWord\Section\CheckBox; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; -use PhpOffice\PhpWord\Style\Cell; -use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Style\Cell; +use PhpOffice\PhpWord\Style\Table as TableStyle; +use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Word2007 base part writer @@ -38,55 +40,31 @@ class Base extends WriterPart /** * Write text element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Text $text + * @param XMLWriter $xmlWriter + * @param Text $text * @param boolean $withoutP */ - protected function _writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) - { + protected function writeText( + XMLWriter $xmlWriter, + Text $text, + $withoutP = false + ) { $styleFont = $text->getFontStyle(); - - $sfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $text->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - + $styleParagraph = $text->getParagraphStyle(); $strText = htmlspecialchars($text->getText()); $strText = String::controlCharacterPHP2OOXML($strText); - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); } - + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $xmlWriter->writeAttribute('xml:space', 'preserve'); $xmlWriter->writeRaw($strText); $xmlWriter->endElement(); - $xmlWriter->endElement(); // w:r - if (!$withoutP) { $xmlWriter->endElement(); // w:p } @@ -95,55 +73,693 @@ class Base extends WriterPart /** * Write textrun element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param TextRun $textrun */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) - { + protected function writeTextRun( + XMLWriter $xmlWriter, + TextRun $textrun + ) { $elements = $textrun->getElements(); $styleParagraph = $textrun->getParagraphStyle(); - - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - $xmlWriter->startElement('w:p'); - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); + $this->writeLink($xmlWriter, $element, true); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element, true); + $this->writeImage($xmlWriter, $element, true); } elseif ($element instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $element, true); + $this->writeFootnote($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } } } + $xmlWriter->endElement(); // w:p + } + + /** + * Write link element + * + * @param XMLWriter $xmlWriter + * @param Link $link + * @param boolean $withoutP + */ + protected function writeLink( + XMLWriter $xmlWriter, + Link $link, + $withoutP = false + ) { + $rID = $link->getRelationId(); + $linkName = $link->getLinkName(); + if (is_null($linkName)) { + $linkName = $link->getLinkSrc(); + } + $styleFont = $link->getFontStyle(); + $styleParagraph = $link->getParagraphStyle(); + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + } + $xmlWriter->startElement('w:hyperlink'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rID); + $xmlWriter->writeAttribute('w:history', '1'); + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text + $xmlWriter->writeRaw($linkName); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:hyperlink + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write title element + * + * @param XMLWriter $xmlWriter + * @param Title $title + */ + protected function writeTitle(XMLWriter $xmlWriter, Title $title) + { + $text = htmlspecialchars($title->getText()); + $text = String::controlCharacterPHP2OOXML($text); + $anchor = $title->getAnchor(); + $bookmarkId = $title->getBookmarkId(); + $style = $title->getStyle(); + + $xmlWriter->startElement('w:p'); + + if (!empty($style)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:pStyle'); + $xmlWriter->writeAttribute('w:val', $style); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:bookmarkStart'); + $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->writeAttribute('w:name', $anchor); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:bookmarkEnd'); + $xmlWriter->writeAttribute('w:id', $bookmarkId); + $xmlWriter->endElement(); $xmlWriter->endElement(); } + /** + * Write preserve text element + * + * @param XMLWriter $xmlWriter + * @param PreserveText $textrun + */ + protected function writePreserveText( + XMLWriter $xmlWriter, + PreserveText $textrun + ) { + $styleFont = $textrun->getFontStyle(); + $styleParagraph = $textrun->getParagraphStyle(); + + $arrText = $textrun->getText(); + if (!is_array($arrText)) { + $arrText = array($arrText); + } + + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + foreach ($arrText as $text) { + if (substr($text, 0, 1) == '{') { + $text = substr($text, 1, -1); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } else { + $text = htmlspecialchars($text); + $text = String::controlCharacterPHP2OOXML($text); + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + + $xmlWriter->endElement(); // p + } + + /** + * Write text break element + * + * @param XMLWriter $xmlWriter + * @param TextBreak $element + */ + protected function writeTextBreak($xmlWriter, TextBreak $element = null) + { + $hasStyle = false; + $styleFont = null; + $styleParagraph = null; + if (!is_null($element)) { + $styleFont = $element->getFontStyle(); + $styleParagraph = $element->getParagraphStyle(); + $hasStyle = !is_null($styleFont) || !is_null($styleParagraph); + } + if ($hasStyle) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + if (!is_null($styleFont)) { + $xmlWriter->startElement('w:pPr'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->endElement(); // w:pPr + } + $xmlWriter->endElement(); // w:p + } else { + // Null element. No paragraph nor font style + $xmlWriter->writeElement('w:p', null); + } + } + + /** + * Write list item element + * + * @param XMLWriter $xmlWriter + * @param ListItem $listItem + */ + protected function writeListItem(XMLWriter $xmlWriter, ListItem $listItem) + { + $textObject = $listItem->getTextObject(); + $depth = $listItem->getDepth(); + $listType = $listItem->getStyle()->getListType(); + $styleParagraph = $textObject->getParagraphStyle(); + + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:pPr'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph, true); + $xmlWriter->startElement('w:numPr'); + $xmlWriter->startElement('w:ilvl'); + $xmlWriter->writeAttribute('w:val', $depth); + $xmlWriter->endElement(); // w:ilvl + $xmlWriter->startElement('w:numId'); + $xmlWriter->writeAttribute('w:val', $listType); + $xmlWriter->endElement(); // w:numId + $xmlWriter->endElement(); // w:numPr + $xmlWriter->endElement(); // w:pPr + $this->writeText($xmlWriter, $textObject, true); + $xmlWriter->endElement(); // w:p + } + + /** + * Write footnote reference element + * + * @param XMLWriter $xmlWriter + * @param Table $table + */ + protected function writeTable(XMLWriter $xmlWriter, Table $table) + { + $_rows = $table->getRows(); + $_cRows = count($_rows); + + if ($_cRows > 0) { + $xmlWriter->startElement('w:tbl'); + + // Table grid + $cellWidths = array(); + for ($i = 0; $i < $_cRows; $i++) { + $row = $_rows[$i]; + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); + } + } + $xmlWriter->startElement('w:tblGrid'); + foreach ($cellWidths as $width) { + $xmlWriter->startElement('w:gridCol'); + if (!is_null($width)) { + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + } + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); // w:tblGrid + + // Table style + $tblStyle = $table->getStyle(); + $tblWidth = $table->getWidth(); + if ($tblStyle instanceof TableStyle) { + $this->writeTableStyle($xmlWriter, $tblStyle, false); + } else { + if (!empty($tblStyle)) { + $xmlWriter->startElement('w:tblPr'); + $xmlWriter->startElement('w:tblStyle'); + $xmlWriter->writeAttribute('w:val', $tblStyle); + $xmlWriter->endElement(); + if (!is_null($tblWidth)) { + $xmlWriter->startElement('w:tblW'); + $xmlWriter->writeAttribute('w:w', $tblWidth); + $xmlWriter->writeAttribute('w:type', 'pct'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + } + + // Table rows + for ($i = 0; $i < $_cRows; $i++) { + $row = $_rows[$i]; + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $cantSplit = $rowStyle->getCantSplit(); + $exactHeight = $rowStyle->getExactHeight(); + + $xmlWriter->startElement('w:tr'); + + if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { + $xmlWriter->startElement('w:trPr'); + if (!is_null($height)) { + $xmlWriter->startElement('w:trHeight'); + $xmlWriter->writeAttribute('w:val', $height); + $xmlWriter->writeAttribute('w:hRule', ($exactHeight ? 'exact' : 'atLeast')); + $xmlWriter->endElement(); + } + if ($tblHeader) { + $xmlWriter->startElement('w:tblHeader'); + $xmlWriter->writeAttribute('w:val', '1'); + $xmlWriter->endElement(); + } + if ($cantSplit) { + $xmlWriter->startElement('w:cantSplit'); + $xmlWriter->writeAttribute('w:val', '1'); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + + foreach ($row->getCells() as $cell) { + $xmlWriter->startElement('w:tc'); + + $cellStyle = $cell->getStyle(); + $width = $cell->getWidth(); + + $xmlWriter->startElement('w:tcPr'); + $xmlWriter->startElement('w:tcW'); + $xmlWriter->writeAttribute('w:w', $width); + $xmlWriter->writeAttribute('w:type', 'dxa'); + $xmlWriter->endElement(); + + if ($cellStyle instanceof Cell) { + $this->writeCellStyle($xmlWriter, $cellStyle); + } + + $xmlWriter->endElement(); + + $_elements = $cell->getElements(); + if (count($_elements) > 0) { + foreach ($_elements as $element) { + if ($element instanceof Text) { + $this->writeText($xmlWriter, $element); + } elseif ($element instanceof TextRun) { + $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof Link) { + $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof TextBreak) { + $this->writeTextBreak($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); + } elseif ($element instanceof Image) { + $this->writeImage($xmlWriter, $element); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element); + } elseif ($element instanceof PreserveText) { + $this->writePreserveText($xmlWriter, $element); + } elseif ($element instanceof CheckBox) { + $this->writeCheckBox($xmlWriter, $element); + } + } + } else { + $this->writeTextBreak($xmlWriter); + } + + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } + } + + /** + * Write image element + * + * @param XMLWriter $xmlWriter + * @param Image $image + * @param boolean $withoutP + */ + protected function writeImage( + XMLWriter $xmlWriter, + Image $image, + $withoutP = false + ) { + $rId = $image->getRelationId(); + + $style = $image->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $align = $style->getAlign(); + $marginTop = $style->getMarginTop(); + $marginLeft = $style->getMarginLeft(); + $wrappingStyle = $style->getWrappingStyle(); + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + + if (!is_null($align)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:jc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + + $xmlWriter->startElement('w:r'); + + $xmlWriter->startElement('w:pict'); + + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + + $imgStyle = ''; + if (null !== $width) { + $imgStyle .= 'width:' . $width . 'px;'; + } + if (null !== $height) { + $imgStyle .= 'height:' . $height . 'px;'; + } + if (null !== $marginTop) { + $imgStyle .= 'margin-top:' . $marginTop . 'in;'; + } + if (null !== $marginLeft) { + $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; + } + + switch ($wrappingStyle) { + case ImageStyle::WRAPPING_STYLE_BEHIND: + $imgStyle .= 'position:absolute;z-index:-251658752;'; + break; + case ImageStyle::WRAPPING_STYLE_SQUARE: + $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + break; + case ImageStyle::WRAPPING_STYLE_TIGHT: + $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; + break; + case ImageStyle::WRAPPING_STYLE_INFRONT: + $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + break; + } + + $xmlWriter->writeAttribute('style', $imgStyle); + + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write watermark element + * + * @param XMLWriter $xmlWriter + * @param Image $image + */ + protected function writeWatermark(XMLWriter $xmlWriter, Image $image) + { + $rId = $image->getRelationId(); + + $style = $image->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $marginLeft = $style->getMarginLeft(); + $marginTop = $style->getMarginTop(); + + $xmlWriter->startElement('w:p'); + + $xmlWriter->startElement('w:r'); + + $xmlWriter->startElement('w:pict'); + + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + + $strStyle = 'position:absolute;'; + $strStyle .= ' width:' . $width . 'px;'; + $strStyle .= ' height:' . $height . 'px;'; + if (!is_null($marginTop)) { + $strStyle .= ' margin-top:' . $marginTop . 'px;'; + } + if (!is_null($marginLeft)) { + $strStyle .= ' margin-left:' . $marginLeft . 'px;'; + } + + $xmlWriter->writeAttribute('style', $strStyle); + + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + } + + /** + * Write object element + * + * @param XMLWriter $xmlWriter + * @param Object $object + */ + protected function writeObject(XMLWriter $xmlWriter, Object $object) + { + $rIdObject = $object->getRelationId(); + $rIdImage = $object->getImageRelationId(); + $shapeId = md5($rIdObject . '_' . $rIdImage); + $objectId = $object->getObjectId(); + $style = $object->getStyle(); + $align = $style->getAlign(); + + $xmlWriter->startElement('w:p'); + if (!is_null($align)) { + $xmlWriter->startElement('w:pPr'); + $xmlWriter->startElement('w:jc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:object'); + $xmlWriter->writeAttribute('w:dxaOrig', '249'); + $xmlWriter->writeAttribute('w:dyaOrig', '160'); + $xmlWriter->startElement('v:shape'); + $xmlWriter->writeAttribute('id', $shapeId); + $xmlWriter->writeAttribute('type', '#_x0000_t75'); + $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); + $xmlWriter->writeAttribute('o:ole', ''); + $xmlWriter->startElement('v:imagedata'); + $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); + $xmlWriter->writeAttribute('o:title', ''); + $xmlWriter->endElement(); // v:imagedata + $xmlWriter->endElement(); // v:shape + $xmlWriter->startElement('o:OLEObject'); + $xmlWriter->writeAttribute('Type', 'Embed'); + $xmlWriter->writeAttribute('ProgID', 'Package'); + $xmlWriter->writeAttribute('ShapeID', $shapeId); + $xmlWriter->writeAttribute('DrawAspect', 'Icon'); + $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); + $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); + $xmlWriter->endElement(); // o:OLEObject + $xmlWriter->endElement(); // w:object + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p + } + + /** + * Write footnote element which links to the actual content in footnotes.xml + * + * @param XMLWriter $xmlWriter + * @param Footnote $footnote + * @param boolean $withoutP + */ + protected function writeFootnote( + XMLWriter $xmlWriter, + Footnote $footnote, + $withoutP = false + ) { + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr + $xmlWriter->startElement('w:footnoteReference'); + $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $xmlWriter->endElement(); // w:footnoteReference + $xmlWriter->endElement(); // w:r + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + + /** + * Write CheckBox + * + * @param boolean $withoutP + * @param boolean $checkState + */ + protected function writeCheckBox( + XMLWriter $xmlWriter, + CheckBox $checkbox, + $withoutP = false, + $checkState = false + ) { + $name = htmlspecialchars($checkbox->getName()); + $name = String::controlCharacterPHP2OOXML($name); + $text = htmlspecialchars($checkbox->getText()); + $text = String::controlCharacterPHP2OOXML($text); + $styleFont = $checkbox->getFontStyle(); + $styleParagraph = $checkbox->getParagraphStyle(); + + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + } + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $xmlWriter->startElement('w:ffData'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', $name); + $xmlWriter->endElement(); //w:name + $xmlWriter->writeAttribute('w:enabled', ''); + $xmlWriter->startElement('w:calcOnExit'); + $xmlWriter->writeAttribute('w:val', '0'); + $xmlWriter->endElement(); //w:calcOnExit + $xmlWriter->startElement('w:checkBox'); + $xmlWriter->writeAttribute('w:sizeAuto', ''); + $xmlWriter->startElement('w:default'); + $xmlWriter->writeAttribute('w:val', ($checkState ? '1' : '0')); + $xmlWriter->endElement(); //w:default + $xmlWriter->endElement(); //w:checkBox + $xmlWriter->endElement(); // w:ffData + $xmlWriter->endElement(); // w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:instrText'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw(' FORMCHECKBOX '); + $xmlWriter->endElement();// w:instrText + $xmlWriter->endElement(); // w:r + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'seperate'); + $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:r + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:fldChar'); + $xmlWriter->writeAttribute('w:fldCharType', 'end'); + $xmlWriter->endElement();// w:fldChar + $xmlWriter->endElement(); // w:r + + $xmlWriter->startElement('w:r'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw($text); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + /** * Write paragraph style * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Style\Paragraph $style + * @param XMLWriter $xmlWriter + * @param Paragraph $style * @param bool $withoutPPR */ - protected function _writeParagraphStyle( + protected function writeParagraphStyle( XMLWriter $xmlWriter, Paragraph $style, $withoutPPR = false @@ -240,173 +856,12 @@ class Base extends WriterPart } /** - * Write link element + * Write font style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Link $link - * @param boolean $withoutP + * @param XMLWriter $xmlWriter + * @param Font $style */ - protected function _writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) - { - $rID = $link->getRelationId(); - $linkName = $link->getLinkName(); - if (is_null($linkName)) { - $linkName = $link->getLinkSrc(); - } - - $styleFont = $link->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $link->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rID); - $xmlWriter->writeAttribute('w:history', '1'); - - $xmlWriter->startElement('w:r'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text - $xmlWriter->writeRaw($linkName); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write preserve text element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\TextRun $textrun - */ - protected function _writePreserveText(XMLWriter $xmlWriter, PreserveText $textrun) - { - $styleFont = $textrun->getFontStyle(); - $styleParagraph = $textrun->getParagraphStyle(); - - $sfIsObject = ($styleFont instanceof Font) ? true : false; - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $arrText = $textrun->getText(); - if (!is_array($arrText)) { - $arrText = array($arrText); - } - - $xmlWriter->startElement('w:p'); - - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - foreach ($arrText as $text) { - - if (substr($text, 0, 1) == '{') { - $text = substr($text, 1, -1); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } else { - $text = htmlspecialchars($text); - $text = String::controlCharacterPHP2OOXML($text); - - $xmlWriter->startElement('w:r'); - - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->endElement(); // p - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - protected function _writeTextStyle(XMLWriter $xmlWriter, Font $style) + protected function writeFontStyle(XMLWriter $xmlWriter, Font $style) { $font = $style->getName(); $bold = $style->getBold(); @@ -504,209 +959,16 @@ class Base extends WriterPart $xmlWriter->endElement(); } - /** - * Write text break element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextBreak $element - */ - protected function _writeTextBreak($xmlWriter, $element = null) - { - $hasStyle = false; - if (!is_null($element)) { - $fontStyle = $element->getFontStyle(); - $sfIsObject = ($fontStyle instanceof Font) ? true : false; - $paragraphStyle = $element->getParagraphStyle(); - $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; - $hasStyle = !is_null($fontStyle) || !is_null($paragraphStyle); - } - if ($hasStyle) { - // Paragraph style - $xmlWriter->startElement('w:p'); - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); - } elseif (!$spIsObject && !is_null($paragraphStyle)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $paragraphStyle); - $xmlWriter->endElement(); // w:pStyle - $xmlWriter->endElement(); // w:pPr - } - // Font style - if (!is_null($fontStyle)) { - $xmlWriter->startElement('w:pPr'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $fontStyle); - } elseif (!$sfIsObject && !is_null($fontStyle)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $fontStyle); - $xmlWriter->endElement(); // w:rStyle - $xmlWriter->endElement(); // w:rPr - } - $xmlWriter->endElement(); // w:pPr - } - $xmlWriter->endElement(); // w:p - } else { - // Null element. No paragraph nor font style - $xmlWriter->writeElement('w:p', null); - } - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Table $table - */ - protected function _writeTable(XMLWriter $xmlWriter, Table $table) - { - $_rows = $table->getRows(); - $_cRows = count($_rows); - - if ($_cRows > 0) { - $xmlWriter->startElement('w:tbl'); - - // Table grid - $cellWidths = array(); - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; - $cells = $row->getCells(); - if (count($cells) <= count($cellWidths)) { - continue; - } - $cellWidths = array(); - foreach ($cells as $cell) { - $cellWidths[] = $cell->getWidth(); - } - } - $xmlWriter->startElement('w:tblGrid'); - foreach ($cellWidths as $width) { - $xmlWriter->startElement('w:gridCol'); - if (!is_null($width)) { - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); // w:tblGrid - - // Table style - $tblStyle = $table->getStyle(); - $tblWidth = $table->getWidth(); - if ($tblStyle instanceof \PhpOffice\PhpWord\Style\Table) { - $this->_writeTableStyle($xmlWriter, $tblStyle, false); - } else { - if (!empty($tblStyle)) { - $xmlWriter->startElement('w:tblPr'); - $xmlWriter->startElement('w:tblStyle'); - $xmlWriter->writeAttribute('w:val', $tblStyle); - $xmlWriter->endElement(); - if (!is_null($tblWidth)) { - $xmlWriter->startElement('w:tblW'); - $xmlWriter->writeAttribute('w:w', $tblWidth); - $xmlWriter->writeAttribute('w:type', 'pct'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - - // Table rows - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; - $height = $row->getHeight(); - $rowStyle = $row->getStyle(); - $tblHeader = $rowStyle->getTblHeader(); - $cantSplit = $rowStyle->getCantSplit(); - $exactHeight = $rowStyle->getExactHeight(); - - $xmlWriter->startElement('w:tr'); - - if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { - $xmlWriter->startElement('w:trPr'); - if (!is_null($height)) { - $xmlWriter->startElement('w:trHeight'); - $xmlWriter->writeAttribute('w:val', $height); - $xmlWriter->writeAttribute('w:hRule', ($exactHeight ? 'exact' : 'atLeast')); - $xmlWriter->endElement(); - } - if ($tblHeader) { - $xmlWriter->startElement('w:tblHeader'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($cantSplit) { - $xmlWriter->startElement('w:cantSplit'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('w:tc'); - - $cellStyle = $cell->getStyle(); - $width = $cell->getWidth(); - - $xmlWriter->startElement('w:tcPr'); - $xmlWriter->startElement('w:tcW'); - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - - if ($cellStyle instanceof Cell) { - $this->_writeCellStyle($xmlWriter, $cellStyle); - } - - $xmlWriter->endElement(); - - $_elements = $cell->getElements(); - if (count($_elements) > 0) { - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); - } elseif ($element instanceof CheckBox) { - $this->_writeCheckBox($xmlWriter, $element); - } - } - } else { - $this->_writeTextBreak($xmlWriter); - } - - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - /** * Write table style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Table $style + * @param XMLWriter $xmlWriter + * @param TableStyle $style * @param boolean $isFullStyle */ - protected function _writeTableStyle( + protected function writeTableStyle( XMLWriter $xmlWriter, - \PhpOffice\PhpWord\Style\Table $style, + TableStyle $style, $isFullStyle = true ) { $bgColor = $style->getBgColor(); @@ -822,7 +1084,7 @@ class Base extends WriterPart // First Row $firstRow = $style->getFirstRow(); if (!is_null($firstRow)) { - $this->_writeRowStyle($xmlWriter, 'firstRow', $firstRow); + $this->writeRowStyle($xmlWriter, 'firstRow', $firstRow); } } } @@ -830,14 +1092,14 @@ class Base extends WriterPart /** * Write row style * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $type - * @param PhpOffice\PhpWord\Style\Table $style + * @param TableStyle $style */ - protected function _writeRowStyle( + protected function writeRowStyle( XMLWriter $xmlWriter, $type, - \PhpOffice\PhpWord\Style\Table $style + TableStyle $style ) { $brdSz = $style->getBorderSize(); $brdCol = $style->getBorderColor(); @@ -847,7 +1109,6 @@ class Base extends WriterPart $bLeft = (!is_null($brdSz[1])) ? true : false; $bRight = (!is_null($brdSz[2])) ? true : false; $bBottom = (!is_null($brdSz[3])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom) ? true : false; $xmlWriter->startElement('w:tblStylePr'); $xmlWriter->writeAttribute('w:type', $type); @@ -900,10 +1161,10 @@ class Base extends WriterPart /** * Write footnote reference element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Cell $style + * @param XMLWriter $xmlWriter + * @param Cell $style */ - protected function _writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) + protected function writeCellStyle(XMLWriter $xmlWriter, Cell $style) { $bgColor = $style->getBgColor(); $valign = $style->getVAlign(); @@ -1007,303 +1268,91 @@ class Base extends WriterPart } /** - * Write image element + * Write individual rels entry * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image - * @param boolean $withoutP + * @param XMLWriter $xmlWriter + * @param int $pId Relationship ID + * @param string $pType Relationship type + * @param string $pTarget Relationship target + * @param string $pTargetMode Relationship target mode */ - protected function _writeImage(XMLWriter $xmlWriter, $image, $withoutP = false) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - $marginTop = $style->getMarginTop(); - $marginLeft = $style->getMarginLeft(); - $wrappingStyle = $style->getWrappingStyle(); - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + protected function writeRelationship( + XMLWriter $xmlWriter, + $pId = 1, + $pType = '', + $pTarget = '', + $pTargetMode = '' + ) { + if ($pType != '' && $pTarget != '') { + if (strpos($pId, 'rId') === false) { + $pId = 'rId' . $pId; } - } - $xmlWriter->startElement('w:r'); + // Write relationship + $xmlWriter->startElement('Relationship'); + $xmlWriter->writeAttribute('Id', $pId); + $xmlWriter->writeAttribute('Type', $pType); + $xmlWriter->writeAttribute('Target', $pTarget); - $xmlWriter->startElement('w:pict'); + if ($pTargetMode != '') { + $xmlWriter->writeAttribute('TargetMode', $pTargetMode); + } - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $imgStyle = ''; - if (null !== $width) { - $imgStyle .= 'width:' . $width . 'px;'; - } - if (null !== $height) { - $imgStyle .= 'height:' . $height . 'px;'; - } - if (null !== $marginTop) { - $imgStyle .= 'margin-top:' . $marginTop . 'in;'; - } - if (null !== $marginLeft) { - $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; - } - - switch ($wrappingStyle) { - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND: - $imgStyle .= 'position:absolute;z-index:-251658752;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE: - $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_TIGHT: - $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_INFRONT: - $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - } - - $xmlWriter->writeAttribute('style', $imgStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image - */ - protected function _writeWatermark(XMLWriter $xmlWriter, $image) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $marginLeft = $style->getMarginLeft(); - $marginTop = $style->getMarginTop(); - - $xmlWriter->startElement('w:p'); - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:pict'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $strStyle = 'position:absolute;'; - $strStyle .= ' width:' . $width . 'px;'; - $strStyle .= ' height:' . $height . 'px;'; - if (!is_null($marginTop)) { - $strStyle .= ' margin-top:' . $marginTop . 'px;'; - } - if (!is_null($marginLeft)) { - $strStyle .= ' margin-left:' . $marginLeft . 'px;'; - } - - $xmlWriter->writeAttribute('style', $strStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write title element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Title $title - */ - protected function _writeTitle(XMLWriter $xmlWriter, Title $title) - { - $text = htmlspecialchars($title->getText()); - $text = String::controlCharacterPHP2OOXML($text); - $anchor = $title->getAnchor(); - $bookmarkId = $title->getBookmarkId(); - $style = $title->getStyle(); - - $xmlWriter->startElement('w:p'); - - if (!empty($style)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $style); $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->writeAttribute('w:name', $anchor); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write footnote element which links to the actual content in footnotes.xml - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote - * @param boolean $withoutP - */ - protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) - { - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); - $xmlWriter->endElement(); // w:rStyle - $xmlWriter->endElement(); // w:rPr - $xmlWriter->startElement('w:footnoteReference'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); - $xmlWriter->endElement(); // w:footnoteReference - - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p + } else { + throw new Exception("Invalid parameters passed."); } } /** - * Write CheckBox + * Write inline paragraph style * - * @param boolean $withoutP - * @param boolean $checkState + * @param XMLWriter $xmlWriter + * @param Paragraph|string $styleParagraph + * @param boolean $withoutPPR */ - protected function _writeCheckBox(XMLWriter $xmlWriter, CheckBox $checkbox, $withoutP = false, $checkState = false) - { - $name = htmlspecialchars($checkbox->getName()); - $name = String::controlCharacterPHP2OOXML($name); - $text = htmlspecialchars($checkbox->getText()); - $text = String::controlCharacterPHP2OOXML($text); - - $styleFont = $checkbox->getFontStyle(); - $sfIsObject = ($styleFont instanceof Font) ? true : false; - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - $styleParagraph = $checkbox->getParagraphStyle(); - $spIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$spIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); + protected function writeInlineParagraphStyle( + XMLWriter $xmlWriter, + $styleParagraph = null, + $withoutPPR = false + ) { + if ($styleParagraph instanceof Paragraph) { + $this->writeParagraphStyle($xmlWriter, $styleParagraph, $withoutPPR); + } else { + if (!is_null($styleParagraph)) { + if (!$withoutPPR) { + $xmlWriter->startElement('w:pPr'); + } $xmlWriter->startElement('w:pStyle'); $xmlWriter->writeAttribute('w:val', $styleParagraph); $xmlWriter->endElement(); + if (!$withoutPPR) { + $xmlWriter->endElement(); + } + } + } + } + + /** + * Write inline font style + * + * @param XMLWriter $xmlWriter + * @param Font|string $styleFont + */ + protected function writeInlineFontStyle( + XMLWriter $xmlWriter, + $styleFont = null + ) { + if ($styleFont instanceof Font) { + $this->writeFontStyle($xmlWriter, $styleFont); + } else { + if (!is_null($styleFont)) { + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', $styleFont); + $xmlWriter->endElement(); $xmlWriter->endElement(); } } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->startElement('w:ffData'); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', $name); - $xmlWriter->endElement(); //w:name - $xmlWriter->writeAttribute('w:enabled', ''); - $xmlWriter->startElement('w:calcOnExit'); - $xmlWriter->writeAttribute('w:val', '0'); - $xmlWriter->endElement(); //w:calcOnExit - $xmlWriter->startElement('w:checkBox'); - $xmlWriter->writeAttribute('w:sizeAuto', ''); - $xmlWriter->startElement('w:default'); - $xmlWriter->writeAttribute('w:val', ($checkState ? '1' : '0')); - $xmlWriter->endElement(); //w:default - $xmlWriter->endElement(); //w:checkBox - $xmlWriter->endElement(); // w:ffData - $xmlWriter->endElement(); // w:fldChar - $xmlWriter->endElement(); // w:r - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw(' FORMCHECKBOX '); - $xmlWriter->endElement();// w:instrText - $xmlWriter->endElement(); // w:r - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'seperate'); - $xmlWriter->endElement();// w:fldChar - $xmlWriter->endElement(); // w:r - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement();// w:fldChar - $xmlWriter->endElement(); // w:r - - $xmlWriter->startElement('w:r'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$sfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); // w:t - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } } } diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 9f8c3fb2..65c75384 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -19,12 +19,12 @@ class ContentTypes extends WriterPart { /** * Write [Content_Types].xml - * @param array $_imageTypes - * @param array $_objectTypes + * @param array $imageTypes + * @param array $objectTypes * @param int $_cHdrs * @param array $footers */ - public function writeContentTypes($_imageTypes, $_objectTypes, $_cHdrs, $footers) + public function writeContentTypes($imageTypes, $objectTypes, $_cHdrs, $footers) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -37,27 +37,27 @@ class ContentTypes extends WriterPart $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); // Rels - $this->_writeDefaultContentType( + $this->writeDefaultContentType( $xmlWriter, 'rels', 'application/vnd.openxmlformats-package.relationships+xml' ); // XML - $this->_writeDefaultContentType( + $this->writeDefaultContentType( $xmlWriter, 'xml', 'application/xml' ); // Add media content-types - foreach ($_imageTypes as $key => $value) { - $this->_writeDefaultContentType($xmlWriter, $key, $value); + foreach ($imageTypes as $key => $value) { + $this->writeDefaultContentType($xmlWriter, $key, $value); } // Add embedding content-types - if (count($_objectTypes) > 0) { - $this->_writeDefaultContentType( + if (count($objectTypes) > 0) { + $this->writeDefaultContentType( $xmlWriter, 'bin', 'application/vnd.openxmlformats-officedocument.oleObject' @@ -65,76 +65,76 @@ class ContentTypes extends WriterPart } // DocProps - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/docProps/app.xml', 'application/vnd.openxmlformats-officedocument.extended-properties+xml' ); - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/docProps/core.xml', 'application/vnd.openxmlformats-package.core-properties+xml' ); // Document - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/document.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' ); // Styles - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/styles.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml' ); // Numbering - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/numbering.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml' ); // Settings - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/settings.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml' ); // Theme1 - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/theme/theme1.xml', 'application/vnd.openxmlformats-officedocument.theme+xml' ); // WebSettings - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/webSettings.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml' ); // Font Table - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/fontTable.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml' ); // Footnotes - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/footnotes.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml' ); for ($i = 1; $i <= $_cHdrs; $i++) { - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/header' . $i . '.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml' @@ -143,7 +143,7 @@ class ContentTypes extends WriterPart for ($i = 1; $i <= count($footers); $i++) { if (!is_null($footers[$i])) { - $this->_writeOverrideContentType( + $this->writeOverrideContentType( $xmlWriter, '/word/footer' . $i . '.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml' @@ -158,32 +158,15 @@ class ContentTypes extends WriterPart return $xmlWriter->getData(); } - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _getImageMimeType($pFile = '') - { - if (file_exists($pFile)) { - $image = getimagesize($pFile); - return image_type_to_mime_type($image[2]); - } else { - throw new Exception("File $pFile does not exist"); - } - } - /** * Write Default XML element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer + * @param XMLWriter $xmlWriter XML Writer * @param string $pPartname Part name * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ - private function _writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type @@ -199,12 +182,12 @@ class ContentTypes extends WriterPart /** * Write Override XML element * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param string $pPartname Part name * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ - private function _writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type @@ -216,4 +199,21 @@ class ContentTypes extends WriterPart throw new Exception("Invalid parameters passed."); } } + + /** + * Get image mime type + * + * @param string $pFile Filename + * @return string Mime Type + * @throws Exception + */ + private function getImageMimeType($pFile = '') + { + if (file_exists($pFile)) { + $image = getimagesize($pFile); + return image_type_to_mime_type($image[2]); + } else { + throw new Exception("File $pFile does not exist"); + } + } } diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 591dfc0e..92c2fab8 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -110,7 +110,7 @@ class DocProps extends WriterPart /** * Write docProps/core.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeDocPropsCore(PhpWord $phpWord = null) { diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 585050df..03184bd1 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -36,7 +36,7 @@ class Document extends Base /** * Write word/document.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeDocument(PhpWord $phpWord = null) { @@ -72,38 +72,38 @@ class Document extends Base $_elements = $section->getElements(); foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); + $this->writeLink($xmlWriter, $element); } elseif ($element instanceof Title) { - $this->_writeTitle($xmlWriter, $element); + $this->writeTitle($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof PageBreak) { - $this->_writePageBreak($xmlWriter); + $this->writePageBreak($xmlWriter); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); + $this->writeListItem($xmlWriter, $element); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); + $this->writeObject($xmlWriter, $element); } elseif ($element instanceof TOC) { - $this->_writeTOC($xmlWriter); + $this->writeTOC($xmlWriter); } elseif ($element instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $element); + $this->writeFootnote($xmlWriter, $element); } elseif ($element instanceof CheckBox) { - $this->_writeCheckBox($xmlWriter, $element); + $this->writeCheckBox($xmlWriter, $element); } } if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); + $this->writeEndSection($xmlWriter, $section); } else { - $this->_writeSection($xmlWriter, $section); + $this->writeSection($xmlWriter, $section); } } } @@ -118,14 +118,14 @@ class Document extends Base /** * Write begin section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ - private function _writeSection(XMLWriter $xmlWriter, Section $section) + private function writeSection(XMLWriter $xmlWriter, Section $section) { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:pPr'); - $this->_writeEndSection($xmlWriter, $section, 3); + $this->writeEndSection($xmlWriter, $section, 3); $xmlWriter->endElement(); $xmlWriter->endElement(); } @@ -133,10 +133,10 @@ class Document extends Base /** * Write end section * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section + * @param XMLWriter $xmlWriter + * @param Section $section */ - private function _writeEndSection(XMLWriter $xmlWriter, Section $section) + private function writeEndSection(XMLWriter $xmlWriter, Section $section) { $settings = $section->getSettings(); $_headers = $section->getHeaders(); @@ -272,9 +272,9 @@ class Document extends Base /** * Write page break element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ - private function _writePageBreak(XMLWriter $xmlWriter) + private function writePageBreak(XMLWriter $xmlWriter) { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); @@ -285,122 +285,12 @@ class Document extends Base $xmlWriter->endElement(); } - /** - * Write list item element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\ListItem $listItem - */ - public function _writeListItem(XMLWriter $xmlWriter, ListItem $listItem) - { - $textObject = $listItem->getTextObject(); - $text = $textObject->getText(); - $styleParagraph = $textObject->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $depth = $listItem->getDepth(); - $listType = $listItem->getStyle()->getListType(); - - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:pPr'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph, true); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:numPr'); - - $xmlWriter->startElement('w:ilvl'); - $xmlWriter->writeAttribute('w:val', $depth); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $listType); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $this->_writeText($xmlWriter, $textObject, true); - - $xmlWriter->endElement(); - } - - /** - * Write object element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Object $object - */ - protected function _writeObject(XMLWriter $xmlWriter, Object $object) - { - $rIdObject = $object->getRelationId(); - $rIdImage = $object->getImageRelationId(); - $shapeId = md5($rIdObject . '_' . $rIdImage); - - $objectId = $object->getObjectId(); - - $style = $object->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - - - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:object'); - $xmlWriter->writeAttribute('w:dxaOrig', '249'); - $xmlWriter->writeAttribute('w:dyaOrig', '160'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('id', $shapeId); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); - $xmlWriter->writeAttribute('o:ole', ''); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->startElement('o:OLEObject'); - $xmlWriter->writeAttribute('Type', 'Embed'); - $xmlWriter->writeAttribute('ProgID', 'Package'); - $xmlWriter->writeAttribute('ShapeID', $shapeId); - $xmlWriter->writeAttribute('DrawAspect', 'Icon'); - $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:r - - $xmlWriter->endElement(); // w:p - } - /** * Write TOC element * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter */ - private function _writeTOC(XMLWriter $xmlWriter) + private function writeTOC(XMLWriter $xmlWriter) { $titles = TOC::getTitles(); $styleFont = TOC::getStyleFont(); @@ -421,7 +311,7 @@ class Document extends Base $xmlWriter->startElement('w:pPr'); if ($isObject && !is_null($styleFont->getParagraphStyle())) { - $this->_writeParagraphStyle($xmlWriter, $styleFont->getParagraphStyle()); + $this->writeParagraphStyle($xmlWriter, $styleFont->getParagraphStyle()); } if ($indent > 0) { @@ -479,7 +369,7 @@ class Document extends Base $xmlWriter->startElement('w:r'); if ($isObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); + $this->writeFontStyle($xmlWriter, $styleFont); } $xmlWriter->startElement('w:t'); diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 20a014f2..53a5ded5 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 document rels part writer */ -class DocumentRels extends WriterPart +class DocumentRels extends Base { /** * Write word/_rels/document.xml.rels @@ -35,7 +35,7 @@ class DocumentRels extends WriterPart $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Relationship word/document.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', @@ -43,7 +43,7 @@ class DocumentRels extends WriterPart ); // Relationship word/numbering.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 2, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering', @@ -51,7 +51,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 3, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings', @@ -59,7 +59,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 4, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', @@ -67,7 +67,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 5, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings', @@ -75,7 +75,7 @@ class DocumentRels extends WriterPart ); // Relationship word/settings.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, 6, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable', @@ -89,7 +89,7 @@ class DocumentRels extends WriterPart $relationId = $relation['rID']; $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, @@ -128,7 +128,7 @@ class DocumentRels extends WriterPart $relationName = $relation['target']; $relationId = $relation['rID']; - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, @@ -142,36 +142,4 @@ class DocumentRels extends WriterPart // Return return $xmlWriter->getData(); } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index d4f68826..4a3b97f6 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -15,6 +15,7 @@ use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Footer as FooterElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -25,9 +26,9 @@ class Footer extends Base /** * Write word/footnotes.xml * - * @param PhpOffice\PhpWord\Section\Footer $footer + * @param FooterElement $footer */ - public function writeFooter(\PhpOffice\PhpWord\Section\Footer $footer) + public function writeFooter(FooterElement $footer) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -50,17 +51,17 @@ class Footer extends Base foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); + $this->writePreserveText($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index d69e0f0c..ce4aba60 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -77,26 +77,18 @@ class Footnotes extends Base /** * Write footnote content, overrides method in parent class * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote + * @param XMLWriter $xmlWriter + * @param Footnote $footnote + * @param boolean $withoutP */ - private function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) + protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) { $xmlWriter->startElement('w:footnote'); $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); $xmlWriter->startElement('w:p'); // Paragraph style - $paragraphStyle = $footnote->getParagraphStyle(); - $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); - } elseif (!$spIsObject && !is_null($paragraphStyle)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $paragraphStyle); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } + $styleParagraph = $footnote->getParagraphStyle(); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); // Reference symbol $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:rPr'); @@ -118,9 +110,9 @@ class Footnotes extends Base if (count($elements) > 0) { foreach ($elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); + $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); + $this->writeLink($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index f9e5c015..d0665de3 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 footnotes rel part writer */ -class FootnotesRels extends WriterPart +class FootnotesRels extends Base { /** * Write word/_rels/footnotes.xml.rels @@ -41,7 +41,7 @@ class FootnotesRels extends WriterPart $relationId = $relation['rID']; $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - $this->_writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); + $this->writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); } $xmlWriter->endElement(); @@ -49,36 +49,4 @@ class FootnotesRels extends WriterPart // Return return $xmlWriter->getData(); } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 50d77e98..03757693 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -15,6 +15,7 @@ use PhpOffice\PhpWord\Section\Table; use PhpOffice\PhpWord\Section\Text; use PhpOffice\PhpWord\Section\TextBreak; use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Section\Header as HeaderElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -25,9 +26,9 @@ class Header extends Base /** * Write word/headerx.xml * - * @param PhpOffice\PhpWord\Section\Header $header + * @param HeaderElement $header */ - public function writeHeader(\PhpOffice\PhpWord\Section\Header $header) + public function writeHeader(HeaderElement $header) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -51,21 +52,21 @@ class Header extends Base foreach ($_elements as $element) { if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); + $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); + $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); + $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { if (!$element->getIsWatermark()) { - $this->_writeImage($xmlWriter, $element); + $this->writeImage($xmlWriter, $element); } else { - $this->_writeWatermark($xmlWriter, $element); + $this->writeWatermark($xmlWriter, $element); } } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); + $this->writePreserveText($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index 19ce58b0..3e41033f 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -16,12 +16,12 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 rels part writer */ -class Rels extends WriterPart +class Rels extends Base { /** * Write _rels/.rels * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeRelationships(PhpWord $phpWord = null) { @@ -38,7 +38,7 @@ class Rels extends WriterPart $relationId = 1; // Relationship word/document.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', @@ -46,7 +46,7 @@ class Rels extends WriterPart ); // Relationship docProps/core.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', @@ -54,7 +54,7 @@ class Rels extends WriterPart ); // Relationship docProps/app.xml - $this->_writeRelationship( + $this->writeRelationship( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', @@ -65,37 +65,4 @@ class Rels extends WriterPart return $xmlWriter->getData(); } - - /** - * Write Override content type - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID. rId will be prepended! - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } } diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index 1c7c05e2..c7b35faf 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -14,28 +14,20 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Table; /** * Word2007 styles part writer */ class Styles extends Base { - /** - * PhpWord object - * - * @var PhpWord - */ - private $phpWord; - /** * Write word/styles.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord */ public function writeStyles(PhpWord $phpWord = null) { - $this->phpWord = $phpWord; - // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -52,7 +44,7 @@ class Styles extends Base ); // Write default styles $styles = Style::getStyles(); - $this->writeDefaultStyles($xmlWriter, $styles); + $this->writeDefaultStyles($xmlWriter, $phpWord, $styles); // Write other styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { @@ -94,10 +86,10 @@ class Styles extends Base $xmlWriter->startElement('w:basedOn'); $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); + $this->writeParagraphStyle($xmlWriter, $paragraphStyle); } - $this->_writeTextStyle($xmlWriter, $style); + $this->writeFontStyle($xmlWriter, $style); $xmlWriter->endElement(); @@ -127,10 +119,10 @@ class Styles extends Base $xmlWriter->endElement(); } - $this->_writeParagraphStyle($xmlWriter, $style); + $this->writeParagraphStyle($xmlWriter, $style); $xmlWriter->endElement(); - } elseif ($style instanceof \PhpOffice\PhpWord\Style\Table) { + } elseif ($style instanceof Table) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'table'); $xmlWriter->writeAttribute('w:customStyle', '1'); @@ -144,7 +136,7 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', '99'); $xmlWriter->endElement(); - $this->_writeTableStyle($xmlWriter, $style); + $this->writeTableStyle($xmlWriter, $style); $xmlWriter->endElement(); // w:style } @@ -160,13 +152,13 @@ class Styles extends Base /** * Write default font and other default styles * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param XMLWriter $xmlWriter * @param array $styles */ - private function writeDefaultStyles(XMLWriter $xmlWriter, $styles) + private function writeDefaultStyles(XMLWriter $xmlWriter, PhpWord $phpWord, $styles) { - $fontName = $this->phpWord->getDefaultFontName(); - $fontSize = $this->phpWord->getDefaultFontSize(); + $fontName = $phpWord->getDefaultFontName(); + $fontSize = $phpWord->getDefaultFontSize(); // Default font $xmlWriter->startElement('w:docDefaults'); @@ -197,7 +189,7 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); // w:name if (array_key_exists('Normal', $styles)) { - $this->_writeParagraphStyle($xmlWriter, $styles['Normal']); + $this->writeParagraphStyle($xmlWriter, $styles['Normal']); } $xmlWriter->endElement(); // w:style diff --git a/src/PhpWord/Writer/Writer.php b/src/PhpWord/Writer/Writer.php index eeba55ca..bc749738 100644 --- a/src/PhpWord/Writer/Writer.php +++ b/src/PhpWord/Writer/Writer.php @@ -22,7 +22,7 @@ abstract class Writer implements IWriter /** * PHPWord object * - * @var PhpOffice\PhpWord\PhpWord + * @var PhpWord */ protected $phpWord = null; From 9d3c2e8ae7964f18f182aa872e10b74fd6ced3cf Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 31 Mar 2014 00:26:41 +0700 Subject: [PATCH 033/146] Update changelog and documentation for PCLZip --- CHANGELOG.md | 1 + docs/general.rst | 40 +++++++++++++++++++++++++++++++++++++++- src/PhpWord/Template.php | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f97c4c07..c785dbf4 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Font: Add `bgColor` to font style to define background using HEX color - @jcarignan GH-168 - Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 - Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 +- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 ### Bugfixes diff --git a/docs/general.rst b/docs/general.rst index 9b25551a..1c810722 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -7,7 +7,8 @@ Basic example ------------- The following is a basic example of the PHPWord library. More examples -are provided in the `samples folder `__. +are provided in the `samples +folder `__. .. code-block:: php @@ -52,6 +53,42 @@ are provided in the `samples folder save('helloWorld.rtf'); +Settings +-------- + +The ``PhpOffice\PhpWord\Settings`` class provides some options that will +affect the behavior of PHPWord. Below are the options. + +XML Writer compatibility +~~~~~~~~~~~~~~~~~~~~~~~~ + +This option sets +```XMLWriter::setIndent`` `__ +and +```XMLWriter::setIndentString`` `__. +The default value of this option is ``true`` (compatible), which is +`required for OpenOffice `__ to +render OOXML document correctly. You can set this option to ``false`` +during development to make the resulting XML file easier to read. + +.. code-block:: php + + PhpOffice\PhpWord\Settings::setCompatibility(false); + +Zip class +~~~~~~~~~ + +By default, PHPWord uses PHP +`ZipArchive `__ to read or write +ZIP compressed archive and the files inside them. If you can't have +ZipArchive installed on your server, you can use pure PHP library +alternative, `PCLZip `__, which +included with PHPWord. + +.. code-block:: php + + PhpOffice\PhpWord\Settings::setZipClass(PhpOffice\PhpWord\Settings::PCLZIP); + Default font ------------ @@ -105,3 +142,4 @@ points to twips. $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Font::centimeterSizeToTwips(2)); + diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 83ff0206..f54d729e 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -21,7 +21,7 @@ class Template /** * ZipArchive object * - * @var \ZipArchive + * @var mixed */ private $_objZip; From 13e5ca0a84a6c4de677b8eaba5899876256ff7f6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 31 Mar 2014 01:13:02 +0700 Subject: [PATCH 034/146] #160 Refactor folders: Element, Container, and Exception - Rename folder Section to Element - Rename folder Exceptions to Exception - Move Section, Header, Footer, Settings to Container folder - Move Element\Footer\PreserveText to Element\PreserveText --- CHANGELOG.md | 1 + src/PhpWord/{Section => Container}/Footer.php | 21 +++-- src/PhpWord/{Section => Container}/Header.php | 23 +++--- src/PhpWord/{ => Container}/Section.php | 77 ++++++++++--------- .../{Section => Container}/Settings.php | 2 +- src/PhpWord/{Section => Element}/CheckBox.php | 2 +- src/PhpWord/{Section => Element}/Footnote.php | 6 +- src/PhpWord/{Section => Element}/Image.php | 10 +-- src/PhpWord/{Section => Element}/Link.php | 2 +- src/PhpWord/{Section => Element}/ListItem.php | 4 +- src/PhpWord/{Section => Element}/Object.php | 2 +- .../{Section => Element}/PageBreak.php | 2 +- .../Footer => Element}/PreserveText.php | 2 +- src/PhpWord/{Section => Element}/Table.php | 6 +- .../{Section => Element}/Table/Cell.php | 42 +++++----- .../{Section => Element}/Table/Row.php | 4 +- src/PhpWord/{Section => Element}/Text.php | 2 +- .../{Section => Element}/TextBreak.php | 2 +- src/PhpWord/{Section => Element}/TextRun.php | 14 ++-- src/PhpWord/{Section => Element}/Title.php | 2 +- .../{Exceptions => Exception}/Exception.php | 2 +- .../InvalidImageException.php | 2 +- .../InvalidObjectException.php | 2 +- .../InvalidStyleException.php | 2 +- .../UnsupportedImageTypeException.php | 2 +- src/PhpWord/Footnote.php | 2 +- src/PhpWord/HashTable.php | 4 +- src/PhpWord/IOFactory.php | 6 +- src/PhpWord/Media.php | 8 +- src/PhpWord/PhpWord.php | 12 +-- src/PhpWord/Reader/Reader.php | 4 +- src/PhpWord/Reader/Word2007.php | 4 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/Shared/ZipStreamWrapper.php | 2 +- src/PhpWord/Style/Font.php | 4 +- src/PhpWord/Style/Paragraph.php | 4 +- src/PhpWord/Template.php | 12 +-- src/PhpWord/Writer/ODText.php | 2 +- src/PhpWord/Writer/ODText/Content.php | 22 +++--- src/PhpWord/Writer/ODText/Manifest.php | 2 +- src/PhpWord/Writer/RTF.php | 22 +++--- src/PhpWord/Writer/Word2007.php | 2 +- src/PhpWord/Writer/Word2007/Base.php | 24 +++--- src/PhpWord/Writer/Word2007/ContentTypes.php | 2 +- src/PhpWord/Writer/Word2007/Document.php | 26 +++---- src/PhpWord/Writer/Word2007/DocumentRels.php | 2 +- src/PhpWord/Writer/Word2007/Footer.php | 14 ++-- src/PhpWord/Writer/Word2007/Footnotes.php | 8 +- src/PhpWord/Writer/Word2007/FootnotesRels.php | 2 +- src/PhpWord/Writer/Word2007/Header.php | 14 ++-- src/PhpWord/Writer/Word2007/Rels.php | 2 +- src/PhpWord/Writer/Word2007/WriterPart.php | 2 +- src/PhpWord/Writer/Writer.php | 2 +- tests/PhpWord/Tests/AutoloaderTest.php | 6 +- .../{Section => Container}/FooterTest.php | 24 +++--- .../{Section => Container}/HeaderTest.php | 26 +++---- .../Tests/{ => Container}/SectionTest.php | 18 ++--- .../{Section => Container}/SettingsTest.php | 12 +-- .../{Section => Element}/CheckBoxTest.php | 8 +- .../{Section => Element}/FootnoteTest.php | 12 +-- .../Tests/{Section => Element}/ImageTest.php | 22 +++--- .../Tests/{Section => Element}/LinkTest.php | 12 +-- .../{Section => Element}/ListItemTest.php | 10 +-- .../Tests/{Section => Element}/ObjectTest.php | 14 ++-- .../{Section => Element}/PageBreakTest.php | 10 +-- .../Footer => Element}/PreserveTextTest.php | 8 +- .../{Section => Element}/Table/CellTest.php | 46 +++++------ .../{Section => Element}/Table/RowTest.php | 12 +-- .../Tests/{Section => Element}/TableTest.php | 14 ++-- .../{Section => Element}/TextBreakTest.php | 8 +- .../{Section => Element}/TextRunTest.php | 24 +++--- .../Tests/{Section => Element}/TextTest.php | 8 +- .../Tests/{Section => Element}/TitleTest.php | 10 +-- .../ExceptionTest.php | 12 +-- .../InvalidImageExceptionTest.php | 12 +-- .../InvalidStyleExceptionTest.php | 12 +-- .../UnsupportedImageTypeExceptionTest.php | 12 +-- tests/PhpWord/Tests/FootnoteTest.php | 2 +- tests/PhpWord/Tests/IOFactoryTest.php | 4 +- tests/PhpWord/Tests/MediaTest.php | 4 +- tests/PhpWord/Tests/PhpWordTest.php | 4 +- tests/PhpWord/Tests/Reader/Word2007Test.php | 2 +- tests/PhpWord/Tests/Style/FontTest.php | 2 +- tests/PhpWord/Tests/Style/ParagraphTest.php | 2 +- tests/PhpWord/Tests/TemplateTest.php | 4 +- tests/PhpWord/Tests/Writer/ODTextTest.php | 6 +- tests/PhpWord/Tests/Writer/RTFTest.php | 4 +- .../Tests/Writer/Word2007/FooterTest.php | 2 +- .../Tests/Writer/Word2007/HeaderTest.php | 2 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 4 +- 90 files changed, 429 insertions(+), 413 deletions(-) rename src/PhpWord/{Section => Container}/Footer.php (87%) rename src/PhpWord/{Section => Container}/Header.php (90%) rename src/PhpWord/{ => Container}/Section.php (83%) rename src/PhpWord/{Section => Container}/Settings.php (99%) rename src/PhpWord/{Section => Element}/CheckBox.php (98%) rename src/PhpWord/{Section => Element}/Footnote.php (96%) rename src/PhpWord/{Section => Element}/Image.php (95%) rename src/PhpWord/{Section => Element}/Link.php (98%) rename src/PhpWord/{Section => Element}/ListItem.php (95%) rename src/PhpWord/{Section => Element}/Object.php (98%) rename src/PhpWord/{Section => Element}/PageBreak.php (89%) rename src/PhpWord/{Section/Footer => Element}/PreserveText.php (98%) rename src/PhpWord/{Section => Element}/Table.php (95%) rename src/PhpWord/{Section => Element}/Table/Cell.php (89%) rename src/PhpWord/{Section => Element}/Table/Row.php (95%) rename src/PhpWord/{Section => Element}/Text.php (98%) rename src/PhpWord/{Section => Element}/TextBreak.php (98%) rename src/PhpWord/{Section => Element}/TextRun.php (91%) rename src/PhpWord/{Section => Element}/Title.php (98%) rename src/PhpWord/{Exceptions => Exception}/Exception.php (86%) rename src/PhpWord/{Exceptions => Exception}/InvalidImageException.php (88%) rename src/PhpWord/{Exceptions => Exception}/InvalidObjectException.php (88%) rename src/PhpWord/{Exceptions => Exception}/InvalidStyleException.php (89%) rename src/PhpWord/{Exceptions => Exception}/UnsupportedImageTypeException.php (88%) rename tests/PhpWord/Tests/{Section => Container}/FooterTest.php (81%) rename tests/PhpWord/Tests/{Section => Container}/HeaderTest.php (85%) rename tests/PhpWord/Tests/{ => Container}/SectionTest.php (86%) rename tests/PhpWord/Tests/{Section => Container}/SettingsTest.php (95%) rename tests/PhpWord/Tests/{Section => Element}/CheckBoxTest.php (91%) rename tests/PhpWord/Tests/{Section => Element}/FootnoteTest.php (87%) rename tests/PhpWord/Tests/{Section => Element}/ImageTest.php (89%) rename tests/PhpWord/Tests/{Section => Element}/LinkTest.php (87%) rename tests/PhpWord/Tests/{Section => Element}/ListItemTest.php (81%) rename tests/PhpWord/Tests/{Section => Element}/ObjectTest.php (86%) rename tests/PhpWord/Tests/{Section => Element}/PageBreakTest.php (65%) rename tests/PhpWord/Tests/{Section/Footer => Element}/PreserveTextTest.php (85%) rename tests/PhpWord/Tests/{Section => Element}/Table/CellTest.php (82%) rename tests/PhpWord/Tests/{Section => Element}/Table/RowTest.php (81%) rename tests/PhpWord/Tests/{Section => Element}/TableTest.php (83%) rename tests/PhpWord/Tests/{Section => Element}/TextBreakTest.php (89%) rename tests/PhpWord/Tests/{Section => Element}/TextRunTest.php (82%) rename tests/PhpWord/Tests/{Section => Element}/TextTest.php (90%) rename tests/PhpWord/Tests/{Section => Element}/TitleTest.php (84%) rename tests/PhpWord/Tests/{Exceptions => Exception}/ExceptionTest.php (55%) rename tests/PhpWord/Tests/{Exceptions => Exception}/InvalidImageExceptionTest.php (52%) rename tests/PhpWord/Tests/{Exceptions => Exception}/InvalidStyleExceptionTest.php (52%) rename tests/PhpWord/Tests/{Exceptions => Exception}/UnsupportedImageTypeExceptionTest.php (50%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c785dbf4..63c295f0 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Documentation: Simplify page level docblock - @ivanlanin GH-179 - Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 - Reader: Rename AbstractReader > Reader - @ivanlanin +- General: Refactor folders: Element, Container, and Exception - @ivanlanin ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Section/Footer.php b/src/PhpWord/Container/Footer.php similarity index 87% rename from src/PhpWord/Section/Footer.php rename to src/PhpWord/Container/Footer.php index 58c439d2..c1e6034e 100755 --- a/src/PhpWord/Section/Footer.php +++ b/src/PhpWord/Container/Footer.php @@ -7,12 +7,17 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; +use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Section\Footer\PreserveText; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; /** * Footer element @@ -56,7 +61,7 @@ class Footer * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text, $styleFont = null, $styleParagraph = null) { @@ -86,7 +91,7 @@ class Footer * Create a new TextRun * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun + * @return \PhpOffice\PhpWord\Element\TextRun */ public function createTextRun($styleParagraph = null) { @@ -99,7 +104,7 @@ class Footer * Add a Table Element * * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table + * @return \PhpOffice\PhpWord\Element\Table */ public function addTable($style = null) { @@ -113,7 +118,7 @@ class Footer * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($src, $style = null) { @@ -146,7 +151,7 @@ class Footer * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText + * @return \PhpOffice\PhpWord\Element\PreserveText */ public function addPreserveText($text, $styleFont = null, $styleParagraph = null) { diff --git a/src/PhpWord/Section/Header.php b/src/PhpWord/Container/Header.php similarity index 90% rename from src/PhpWord/Section/Header.php rename to src/PhpWord/Container/Header.php index 5a89c266..5b6fce42 100755 --- a/src/PhpWord/Section/Header.php +++ b/src/PhpWord/Container/Header.php @@ -7,12 +7,17 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; +use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Section\Footer\PreserveText; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; /** * Header element @@ -85,7 +90,7 @@ class Header * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text, $styleFont = null, $styleParagraph = null) { @@ -115,7 +120,7 @@ class Header * Create a new TextRun * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun + * @return \PhpOffice\PhpWord\Element\TextRun */ public function createTextRun($styleParagraph = null) { @@ -128,7 +133,7 @@ class Header * Add a Table Element * * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table + * @return \PhpOffice\PhpWord\Element\Table */ public function addTable($style = null) { @@ -142,7 +147,7 @@ class Header * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($src, $style = null) { @@ -175,7 +180,7 @@ class Header * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText + * @return \PhpOffice\PhpWord\Element\PreserveText */ public function addPreserveText($text, $styleFont = null, $styleParagraph = null) { @@ -192,7 +197,7 @@ class Header * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addWatermark($src, $style = null) { diff --git a/src/PhpWord/Section.php b/src/PhpWord/Container/Section.php similarity index 83% rename from src/PhpWord/Section.php rename to src/PhpWord/Container/Section.php index 090ca236..a3002cb3 100644 --- a/src/PhpWord/Section.php +++ b/src/PhpWord/Container/Section.php @@ -7,22 +7,27 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord; +namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exceptions\InvalidObjectException; -use PhpOffice\PhpWord\Section\Footer; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Header; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\PageBreak; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Title; -use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Exception\InvalidImageException; +use PhpOffice\PhpWord\Exception\InvalidObjectException; +use PhpOffice\PhpWord\Footnote; +use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\TOC; +use PhpOffice\PhpWord\Container\Footer; +use PhpOffice\PhpWord\Container\Header; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Title; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\String; /** @@ -40,7 +45,7 @@ class Section /** * Section settings * - * @var \PhpOffice\PhpWord\Section\Settings + * @var \PhpOffice\PhpWord\Container\Settings */ private $_settings; @@ -61,7 +66,7 @@ class Section /** * Section Footer * - * @var \PhpOffice\PhpWord\Section\Footer + * @var \PhpOffice\PhpWord\Container\Footer */ private $_footer = null; @@ -75,7 +80,7 @@ class Section public function __construct($sectionCount, $settings = null) { $this->_sectionCount = $sectionCount; - $this->_settings = new \PhpOffice\PhpWord\Section\Settings(); + $this->_settings = new \PhpOffice\PhpWord\Container\Settings(); $this->setSettings($settings); } @@ -99,7 +104,7 @@ class Section /** * Get Section Settings * - * @return \PhpOffice\PhpWord\Section\Settings + * @return \PhpOffice\PhpWord\Container\Settings */ public function getSettings() { @@ -112,7 +117,7 @@ class Section * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text, $styleFont = null, $styleParagraph = null) { @@ -131,7 +136,7 @@ class Section * @param string $linkName * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Link + * @return \PhpOffice\PhpWord\Element\Link */ public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) { @@ -178,7 +183,7 @@ class Section * Add a Table Element * * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table + * @return \PhpOffice\PhpWord\Element\Table */ public function addTable($style = null) { @@ -195,7 +200,7 @@ class Section * @param mixed $styleFont * @param mixed $styleList * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\ListItem + * @return \PhpOffice\PhpWord\Element\ListItem */ public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) { @@ -210,11 +215,11 @@ class Section /** * Add a OLE-Object Element * - * All exceptions should be handled by PhpOffice\PhpWord\Section\Object + * All exceptions should be handled by PhpOffice\PhpWord\Element\Object * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Object + * @return \PhpOffice\PhpWord\Element\Object */ public function addObject($src, $style = null) { @@ -225,7 +230,7 @@ class Section if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { $ext = substr($ext, 0, -1); } - $icon = __DIR__ . "/_staticDocParts/_{$ext}.png"; + $icon = __DIR__ . "/../_staticDocParts/_{$ext}.png"; $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); $data = Media::addSectionMediaElement($src, 'oleObject'); $rID = $data[0]; @@ -243,11 +248,11 @@ class Section /** * Add image element * - * All exceptions should be handled by PhpOffice\PhpWord\Section\Image + * All exceptions should be handled by PhpOffice\PhpWord\Element\Image * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($src, $style = null) { @@ -290,7 +295,7 @@ class Section * * @param string $text * @param int $depth - * @return \PhpOffice\PhpWord\Section\Title + * @return \PhpOffice\PhpWord\Element\Title */ public function addTitle($text, $depth = 1) { @@ -321,7 +326,7 @@ class Section * Create a new TextRun * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun + * @return \PhpOffice\PhpWord\Element\TextRun */ public function createTextRun($styleParagraph = null) { @@ -343,7 +348,7 @@ class Section /** * Create a new Header * - * @return \PhpOffice\PhpWord\Section\Header + * @return \PhpOffice\PhpWord\Container\Header */ public function createHeader() { @@ -381,7 +386,7 @@ class Section /** * Create a new Footer * - * @return \PhpOffice\PhpWord\Section\Footer + * @return \PhpOffice\PhpWord\Container\Footer */ public function createFooter() { @@ -393,7 +398,7 @@ class Section /** * Get footer element * - * @return \PhpOffice\PhpWord\Section\Footer + * @return \PhpOffice\PhpWord\Container\Footer */ public function getFooter() { @@ -404,11 +409,11 @@ class Section * Create a new Footnote Element * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footnote + * @return \PhpOffice\PhpWord\Element\Footnote */ public function createFootnote($styleParagraph = null) { - $footnote = new \PhpOffice\PhpWord\Section\Footnote($styleParagraph); + $footnote = new \PhpOffice\PhpWord\Element\Footnote($styleParagraph); $refID = Footnote::addFootnoteElement($footnote); $footnote->setReferenceId($refID); $this->_elementCollection[] = $footnote; @@ -422,7 +427,7 @@ class Section * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\CheckBox + * @return \PhpOffice\PhpWord\Element\CheckBox */ public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) { diff --git a/src/PhpWord/Section/Settings.php b/src/PhpWord/Container/Settings.php similarity index 99% rename from src/PhpWord/Section/Settings.php rename to src/PhpWord/Container/Settings.php index 2dbfe2d8..daf5d13b 100644 --- a/src/PhpWord/Section/Settings.php +++ b/src/PhpWord/Container/Settings.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Container; /** * Section settings diff --git a/src/PhpWord/Section/CheckBox.php b/src/PhpWord/Element/CheckBox.php similarity index 98% rename from src/PhpWord/Section/CheckBox.php rename to src/PhpWord/Element/CheckBox.php index 5e101d9f..9a3fcc79 100644 --- a/src/PhpWord/Section/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Section/Footnote.php b/src/PhpWord/Element/Footnote.php similarity index 96% rename from src/PhpWord/Section/Footnote.php rename to src/PhpWord/Element/Footnote.php index c86d8e44..d1cb61cf 100644 --- a/src/PhpWord/Section/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Paragraph; @@ -67,7 +67,7 @@ class Footnote * * @param string $text * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text = null, $styleFont = null) { @@ -97,7 +97,7 @@ class Footnote * @param string $linkSrc * @param string $linkName * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Link + * @return \PhpOffice\PhpWord\Element\Link */ public function addLink($linkSrc, $linkName = null, $styleFont = null) { diff --git a/src/PhpWord/Section/Image.php b/src/PhpWord/Element/Image.php similarity index 95% rename from src/PhpWord/Section/Image.php rename to src/PhpWord/Element/Image.php index 9f5a7838..89ee6f37 100755 --- a/src/PhpWord/Section/Image.php +++ b/src/PhpWord/Element/Image.php @@ -7,10 +7,10 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; -use PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException; +use PhpOffice\PhpWord\Exception\InvalidImageException; +use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; /** * Image element @@ -86,8 +86,8 @@ class Image * @param string $source * @param mixed $style * @param bool $isWatermark - * @throws \PhpOffice\PhpWord\Exceptions\InvalidImageException - * @throws \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException + * @throws \PhpOffice\PhpWord\Exception\InvalidImageException + * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function __construct($source, $style = null, $isWatermark = false) { diff --git a/src/PhpWord/Section/Link.php b/src/PhpWord/Element/Link.php similarity index 98% rename from src/PhpWord/Section/Link.php rename to src/PhpWord/Element/Link.php index 240d0445..1b6cf22a 100644 --- a/src/PhpWord/Section/Link.php +++ b/src/PhpWord/Element/Link.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Section/ListItem.php b/src/PhpWord/Element/ListItem.php similarity index 95% rename from src/PhpWord/Section/ListItem.php rename to src/PhpWord/Element/ListItem.php index 3981814e..e920d4b8 100644 --- a/src/PhpWord/Section/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; /** * List item element @@ -24,7 +24,7 @@ class ListItem /** * Textrun * - * @var \PhpOffice\PhpWord\Section\Text + * @var \PhpOffice\PhpWord\Element\Text */ private $_textObject; diff --git a/src/PhpWord/Section/Object.php b/src/PhpWord/Element/Object.php similarity index 98% rename from src/PhpWord/Section/Object.php rename to src/PhpWord/Element/Object.php index 9b6cc328..61bf6f8e 100644 --- a/src/PhpWord/Section/Object.php +++ b/src/PhpWord/Element/Object.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; /** * Object element diff --git a/src/PhpWord/Section/PageBreak.php b/src/PhpWord/Element/PageBreak.php similarity index 89% rename from src/PhpWord/Section/PageBreak.php rename to src/PhpWord/Element/PageBreak.php index e12c3e3d..4e49582d 100644 --- a/src/PhpWord/Section/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; /** * Page break element diff --git a/src/PhpWord/Section/Footer/PreserveText.php b/src/PhpWord/Element/PreserveText.php similarity index 98% rename from src/PhpWord/Section/Footer/PreserveText.php rename to src/PhpWord/Element/PreserveText.php index 6fbd7bba..453e9b84 100644 --- a/src/PhpWord/Section/Footer/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section\Footer; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Section/Table.php b/src/PhpWord/Element/Table.php similarity index 95% rename from src/PhpWord/Section/Table.php rename to src/PhpWord/Element/Table.php index aff9a23a..fc168349 100644 --- a/src/PhpWord/Section/Table.php +++ b/src/PhpWord/Element/Table.php @@ -7,9 +7,9 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Section\Table\Row; +use PhpOffice\PhpWord\Element\Table\Row; /** * Table element @@ -98,7 +98,7 @@ class Table * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table\Cell + * @return \PhpOffice\PhpWord\Element\Table\Cell */ public function addCell($width = null, $style = null) { diff --git a/src/PhpWord/Section/Table/Cell.php b/src/PhpWord/Element/Table/Cell.php similarity index 89% rename from src/PhpWord/Section/Table/Cell.php rename to src/PhpWord/Element/Table/Cell.php index e0004350..0e0d688e 100755 --- a/src/PhpWord/Section/Table/Cell.php +++ b/src/PhpWord/Element/Table/Cell.php @@ -7,21 +7,21 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section\Table; +namespace PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Exceptions\Exception; -use PhpOffice\PhpWord\Exceptions\InvalidObjectException; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Exception\InvalidObjectException; +use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\String; /** @@ -100,7 +100,7 @@ class Cell * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text, $styleFont = null, $styleParagraph = null) { @@ -118,7 +118,7 @@ class Cell * @param string $linkSrc * @param string $linkName * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Link + * @return \PhpOffice\PhpWord\Element\Link */ public function addLink($linkSrc, $linkName = null, $style = null) { @@ -165,7 +165,7 @@ class Cell * @param int $depth * @param mixed $styleText * @param mixed $styleList - * @return \PhpOffice\PhpWord\Section\ListItem + * @return \PhpOffice\PhpWord\Element\ListItem */ public function addListItem($text, $depth = 0, $styleText = null, $styleList = null) { @@ -182,7 +182,7 @@ class Cell * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($src, $style = null) { @@ -220,7 +220,7 @@ class Cell * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Object + * @return \PhpOffice\PhpWord\Element\Object */ public function addObject($src, $style = null) { @@ -262,7 +262,7 @@ class Cell * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText + * @return \PhpOffice\PhpWord\Element\PreserveText */ public function addPreserveText($text, $styleFont = null, $styleParagraph = null) { @@ -282,7 +282,7 @@ class Cell * Create a new TextRun * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun + * @return \PhpOffice\PhpWord\Element\TextRun */ public function createTextRun($styleParagraph = null) { @@ -298,7 +298,7 @@ class Cell * @param string $text * @param mixed $styleFont * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\CheckBox + * @return \PhpOffice\PhpWord\Element\CheckBox */ public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) { diff --git a/src/PhpWord/Section/Table/Row.php b/src/PhpWord/Element/Table/Row.php similarity index 95% rename from src/PhpWord/Section/Table/Row.php rename to src/PhpWord/Element/Table/Row.php index 8410f571..c027d373 100644 --- a/src/PhpWord/Section/Table/Row.php +++ b/src/PhpWord/Element/Table/Row.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section\Table; +namespace PhpOffice\PhpWord\Element\Table; /** * Table row element @@ -83,7 +83,7 @@ class Row * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table\Cell + * @return \PhpOffice\PhpWord\Element\Table\Cell */ public function addCell($width = null, $style = null) { diff --git a/src/PhpWord/Section/Text.php b/src/PhpWord/Element/Text.php similarity index 98% rename from src/PhpWord/Section/Text.php rename to src/PhpWord/Element/Text.php index 4e228cda..75e1727e 100644 --- a/src/PhpWord/Section/Text.php +++ b/src/PhpWord/Element/Text.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Section/TextBreak.php b/src/PhpWord/Element/TextBreak.php similarity index 98% rename from src/PhpWord/Section/TextBreak.php rename to src/PhpWord/Element/TextBreak.php index 4df4c780..39f3ac16 100755 --- a/src/PhpWord/Section/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Section/TextRun.php b/src/PhpWord/Element/TextRun.php similarity index 91% rename from src/PhpWord/Section/TextRun.php rename to src/PhpWord/Element/TextRun.php index bcb5173a..a890bb04 100755 --- a/src/PhpWord/Section/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -7,9 +7,9 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; +use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Style\Font; @@ -65,7 +65,7 @@ class TextRun * * @param string $text * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Text + * @return \PhpOffice\PhpWord\Element\Text */ public function addText($text = null, $styleFont = null) { @@ -83,7 +83,7 @@ class TextRun * @param string $linkSrc * @param string $linkName * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Link + * @return \PhpOffice\PhpWord\Element\Link */ public function addLink($linkSrc, $linkName = null, $styleFont = null) { @@ -105,7 +105,7 @@ class TextRun * * @param string $imageSrc * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image + * @return \PhpOffice\PhpWord\Element\Image */ public function addImage($imageSrc, $style = null) { @@ -138,11 +138,11 @@ class TextRun * Create a new Footnote Element * * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footnote + * @return \PhpOffice\PhpWord\Element\Footnote */ public function createFootnote($styleParagraph = null) { - $footnote = new \PhpOffice\PhpWord\Section\Footnote($styleParagraph); + $footnote = new \PhpOffice\PhpWord\Element\Footnote($styleParagraph); $refID = \PhpOffice\PhpWord\Footnote::addFootnoteElement($footnote); $footnote->setReferenceId($refID); $this->_elementCollection[] = $footnote; diff --git a/src/PhpWord/Section/Title.php b/src/PhpWord/Element/Title.php similarity index 98% rename from src/PhpWord/Section/Title.php rename to src/PhpWord/Element/Title.php index c93f6687..3921d66c 100644 --- a/src/PhpWord/Section/Title.php +++ b/src/PhpWord/Element/Title.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; /** * Title element diff --git a/src/PhpWord/Exceptions/Exception.php b/src/PhpWord/Exception/Exception.php similarity index 86% rename from src/PhpWord/Exceptions/Exception.php rename to src/PhpWord/Exception/Exception.php index 44323baa..470698a8 100755 --- a/src/PhpWord/Exceptions/Exception.php +++ b/src/PhpWord/Exception/Exception.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Exceptions; +namespace PhpOffice\PhpWord\Exception; /** * General exception diff --git a/src/PhpWord/Exceptions/InvalidImageException.php b/src/PhpWord/Exception/InvalidImageException.php similarity index 88% rename from src/PhpWord/Exceptions/InvalidImageException.php rename to src/PhpWord/Exception/InvalidImageException.php index 319a6203..c8d2143c 100644 --- a/src/PhpWord/Exceptions/InvalidImageException.php +++ b/src/PhpWord/Exception/InvalidImageException.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Exceptions; +namespace PhpOffice\PhpWord\Exception; /** * Exception used for when an image is not found diff --git a/src/PhpWord/Exceptions/InvalidObjectException.php b/src/PhpWord/Exception/InvalidObjectException.php similarity index 88% rename from src/PhpWord/Exceptions/InvalidObjectException.php rename to src/PhpWord/Exception/InvalidObjectException.php index c6a89ac7..b27de805 100644 --- a/src/PhpWord/Exceptions/InvalidObjectException.php +++ b/src/PhpWord/Exception/InvalidObjectException.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Exceptions; +namespace PhpOffice\PhpWord\Exception; /** * Exception used for when an image is not found diff --git a/src/PhpWord/Exceptions/InvalidStyleException.php b/src/PhpWord/Exception/InvalidStyleException.php similarity index 89% rename from src/PhpWord/Exceptions/InvalidStyleException.php rename to src/PhpWord/Exception/InvalidStyleException.php index 9b22e0ae..37290e63 100644 --- a/src/PhpWord/Exceptions/InvalidStyleException.php +++ b/src/PhpWord/Exception/InvalidStyleException.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Exceptions; +namespace PhpOffice\PhpWord\Exception; use InvalidArgumentException; diff --git a/src/PhpWord/Exceptions/UnsupportedImageTypeException.php b/src/PhpWord/Exception/UnsupportedImageTypeException.php similarity index 88% rename from src/PhpWord/Exceptions/UnsupportedImageTypeException.php rename to src/PhpWord/Exception/UnsupportedImageTypeException.php index a2ea1ee9..2b1a25ce 100644 --- a/src/PhpWord/Exceptions/UnsupportedImageTypeException.php +++ b/src/PhpWord/Exception/UnsupportedImageTypeException.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Exceptions; +namespace PhpOffice\PhpWord\Exception; /** * Exception used for when an image type is unsupported diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 69228ee8..af104bc8 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -33,7 +33,7 @@ class Footnote * * @return int Reference ID */ - public static function addFootnoteElement(\PhpOffice\PhpWord\Section\Footnote $footnote) + public static function addFootnoteElement(\PhpOffice\PhpWord\Element\Footnote $footnote) { $refID = self::countFootnoteElements() + 2; diff --git a/src/PhpWord/HashTable.php b/src/PhpWord/HashTable.php index 97e9be45..93bcb689 100644 --- a/src/PhpWord/HashTable.php +++ b/src/PhpWord/HashTable.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * Hash table @@ -48,7 +48,7 @@ class HashTable * Add HashTable items from source * * @param \PhpOffice\PhpWord\IComparable[] $pSource Source array to create HashTable from - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function addFromSource($pSource = null) { diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 6965e270..f99f7a00 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * IO factory @@ -22,7 +22,7 @@ abstract class IOFactory * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $name * @return \PhpOffice\PhpWord\Writer\IWriter - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public static function createWriter(PhpWord $phpWord, $name) { @@ -39,7 +39,7 @@ abstract class IOFactory * * @param string $name * @return \PhpOffice\PhpWord\Reader\IReader - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public static function createReader($name) { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index a9a9a6af..35800f92 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Element\Image; /** * Media @@ -53,7 +53,7 @@ class Media * * @param string $src * @param string $type - * @param \PhpOffice\PhpWord\Section\Image $image + * @param \PhpOffice\PhpWord\Element\Image $image * @return mixed */ public static function addSectionMediaElement($src, $type, Image $image = null) @@ -165,7 +165,7 @@ class Media * * @param int $headerCount * @param string $src - * @param \PhpOffice\PhpWord\Section\Image $image + * @param \PhpOffice\PhpWord\Element\Image $image * @return int */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) @@ -228,7 +228,7 @@ class Media * * @param int $footerCount * @param string $src - * @param \PhpOffice\PhpWord\Section\Image $image + * @param \PhpOffice\PhpWord\Element\Image $image * @return int */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index e0506803..894d7df7 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -10,8 +10,8 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Exceptions\Exception; -use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Container\Section; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Template; @@ -94,8 +94,8 @@ class PhpWord /** * Create new section * - * @param \PhpOffice\PhpWord\Section\Settings $settings - * @return \PhpOffice\PhpWord\Section + * @param \PhpOffice\PhpWord\Container\Settings $settings + * @return \PhpOffice\PhpWord\Container\Section */ public function createSection($settings = null) { @@ -216,7 +216,7 @@ class PhpWord /** * Get all sections * - * @return \PhpOffice\PhpWord\Section[] + * @return \PhpOffice\PhpWord\Container\Section[] */ public function getSections() { @@ -228,7 +228,7 @@ class PhpWord * * @param string $filename Fully qualified filename. * @return \PhpOffice\PhpWord\Template - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function loadTemplate($filename) { diff --git a/src/PhpWord/Reader/Reader.php b/src/PhpWord/Reader/Reader.php index 153a4013..e50ca7b5 100644 --- a/src/PhpWord/Reader/Reader.php +++ b/src/PhpWord/Reader/Reader.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * Reader abstract class @@ -60,7 +60,7 @@ abstract class Reader implements IReader * * @param string $pFilename * @return resource - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function openFile($pFilename) { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 9161d162..12cf4e6b 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * Reader for Word2007 @@ -24,7 +24,7 @@ class Word2007 extends Reader implements IReader * * @param string $pFilename * @return bool - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function canRead($pFilename) { diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index ae22357a..f207385c 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Shared; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; // @codeCoverageIgnoreStart if (!defined('PCLZIP_TEMPORARY_DIR')) { diff --git a/src/PhpWord/Shared/ZipStreamWrapper.php b/src/PhpWord/Shared/ZipStreamWrapper.php index 87e17983..23b69d84 100644 --- a/src/PhpWord/Shared/ZipStreamWrapper.php +++ b/src/PhpWord/Shared/ZipStreamWrapper.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Shared; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; /** diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index d1f5353a..cc1f530c 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -10,7 +10,7 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Exceptions\InvalidStyleException; +use PhpOffice\PhpWord\Exception\InvalidStyleException; /** * Font style @@ -513,7 +513,7 @@ class Font * * @param int|float|string $lineHeight * @return $this - * @throws \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) { diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 982aee44..dbb04610 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Exceptions\InvalidStyleException; +use PhpOffice\PhpWord\Exception\InvalidStyleException; /** * Paragraph style @@ -468,7 +468,7 @@ class Paragraph * * @param int|float|string $lineHeight * @return $this - * @throws \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) { diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index f54d729e..0711ecd5 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\String; @@ -44,7 +44,7 @@ class Template * Create a new Template Object * * @param string $strFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct($strFilename) { @@ -71,7 +71,7 @@ class Template * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { @@ -147,7 +147,7 @@ class Template * * @param int $offset * @return int - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ private function _findRowStart($offset) { @@ -193,7 +193,7 @@ class Template * * @param string $search * @param int $numberOfClones - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function cloneRow($search, $numberOfClones) { @@ -247,7 +247,7 @@ class Template * Save XML to temporary file * * @return string - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save() { diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 7ff31bf0..72955ef1 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\HashTable; use PhpOffice\PhpWord\Settings; diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 2e9a61e6..ccbdcfce 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -10,17 +10,17 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Section; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\PageBreak; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Title; +use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Title; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 31168e3d..69949c73 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index e37e53b3..b5ce20a7 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -9,19 +9,19 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\HashTable; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\PageBreak; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Title; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Title; use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 687bf8d2..5f247707 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 3acf6c1d..b6e4c32c 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -10,18 +10,18 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\Title; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\Footnote; -use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\Title; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 65c75384..98121133 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 03184bd1..c4f8278f 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -10,19 +10,19 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Section; -use PhpOffice\PhpWord\Section\Footnote; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\PageBreak; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Title; -use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Title; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 53a5ded5..648d0864 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index 4a3b97f6..de2bf44d 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -9,13 +9,13 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Footer as FooterElement; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Container\Footer as FooterElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index ce4aba60..d8ba4352 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -9,10 +9,10 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Section\Footnote; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\TextBreak; +use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index d0665de3..405df69f 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 03757693..07a16ec7 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -9,13 +9,13 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Section\Footer\PreserveText; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Header as HeaderElement; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Container\Header as HeaderElement; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index 3e41033f..a675057f 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/src/PhpWord/Writer/Word2007/WriterPart.php b/src/PhpWord/Writer/Word2007/WriterPart.php index ead47239..a61662e9 100755 --- a/src/PhpWord/Writer/Word2007/WriterPart.php +++ b/src/PhpWord/Writer/Word2007/WriterPart.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Writer\IWriter; use PhpOffice\PhpWord\Shared\XMLWriter; diff --git a/src/PhpWord/Writer/Writer.php b/src/PhpWord/Writer/Writer.php index bc749738..e53d215a 100644 --- a/src/PhpWord/Writer/Writer.php +++ b/src/PhpWord/Writer/Writer.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; /** diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index 549f05a8..ac2f4a78 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -45,11 +45,11 @@ class AutoloaderTest extends \PHPUnit_Framework_TestCase 'classes outside of the PhpOffice\\PhpWord namespace' ); // TODO change this class to the main PhpWord class when it is namespaced - Autoloader::autoload('PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException'); + Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); $this->assertTrue( - \in_array('PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException', \get_declared_classes()), + \in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', \get_declared_classes()), 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' . - 'PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException class' + 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' ); } } diff --git a/tests/PhpWord/Tests/Section/FooterTest.php b/tests/PhpWord/Tests/Container/FooterTest.php similarity index 81% rename from tests/PhpWord/Tests/Section/FooterTest.php rename to tests/PhpWord/Tests/Container/FooterTest.php index d14f125c..d9988ac5 100644 --- a/tests/PhpWord/Tests/Section/FooterTest.php +++ b/tests/PhpWord/Tests/Container/FooterTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Container; -use PhpOffice\PhpWord\Section\Footer; +use PhpOffice\PhpWord\Container\Footer; /** - * Test class for PhpOffice\PhpWord\Section\Footer + * Test class for PhpOffice\PhpWord\Container\Footer * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oFooter = new Footer($iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer', $oFooter); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Footer', $oFooter); $this->assertEquals($oFooter->getFooterCount(), $iVal); } @@ -39,7 +39,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addText('text'); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } /** @@ -51,7 +51,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertEquals($element->getText(), 'ééé'); } @@ -76,7 +76,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->createTextRun(); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); } /** @@ -88,7 +88,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addTable(); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element); } /** @@ -102,7 +102,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element2 = $oFooter->addMemoryImage($src); // @deprecated $this->assertCount(2, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); } /** @@ -116,7 +116,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -128,7 +128,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addPreserveText('text'); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } /** @@ -140,7 +140,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } diff --git a/tests/PhpWord/Tests/Section/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php similarity index 85% rename from tests/PhpWord/Tests/Section/HeaderTest.php rename to tests/PhpWord/Tests/Container/HeaderTest.php index edc5d2c6..df1435de 100644 --- a/tests/PhpWord/Tests/Section/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Container; -use PhpOffice\PhpWord\Section\Header; +use PhpOffice\PhpWord\Container\Header; /** - * Test class for PhpOffice\PhpWord\Section\Header + * Test class for PhpOffice\PhpWord\Container\Header * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oHeader = new Header($iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Header', $oHeader); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Header', $oHeader); $this->assertEquals($oHeader->getHeaderCount(), $iVal); $this->assertEquals($oHeader->getType(), Header::AUTO); } @@ -39,7 +39,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $oHeader = new Header(1); $element = $oHeader->addText('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); $this->assertEquals($element->getText(), 'text'); } @@ -52,7 +52,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $oHeader = new Header(1); $element = $oHeader->addText(utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); $this->assertEquals($element->getText(), 'ééé'); } @@ -85,7 +85,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $oHeader = new Header(1); $element = $oHeader->createTextRun(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); $this->assertCount(1, $oHeader->getElements()); } @@ -96,7 +96,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $oHeader = new Header(1); $element = $oHeader->addTable(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element); $this->assertCount(1, $oHeader->getElements()); } @@ -111,7 +111,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element2 = $oHeader->addMemoryImage($src); // @deprecated $this->assertCount(2, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); } /** @@ -125,7 +125,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -137,7 +137,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element = $oHeader->addPreserveText('text'); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } /** @@ -149,7 +149,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element = $oHeader->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } @@ -163,7 +163,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element = $oHeader->addWatermark($src); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** diff --git a/tests/PhpWord/Tests/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php similarity index 86% rename from tests/PhpWord/Tests/SectionTest.php rename to tests/PhpWord/Tests/Container/SectionTest.php index 48b5bb73..a61498ea 100644 --- a/tests/PhpWord/Tests/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -7,13 +7,13 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests; +namespace PhpOffice\PhpWord\Tests\Container; -use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Container\Section; use PhpOffice\PhpWord\Style; /** - * Test class for PhpOffice\PhpWord\Section + * Test class for PhpOffice\PhpWord\Container\Section * * @runTestsInSeparateProcesses */ @@ -71,8 +71,8 @@ class SectionTest extends \PHPUnit_Framework_TestCase */ public function testAddElements() { - $objectSource = __DIR__ . "/_files/documents/reader.docx"; - $imageSource = __DIR__ . "/_files/images/PhpWord.png"; + $objectSource = __DIR__ . "/../_files/documents/reader.docx"; + $imageSource = __DIR__ . "/../_files/images/PhpWord.png"; $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; $section = new Section(0); @@ -97,7 +97,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase 'Title', 'TextRun', 'Footnote', 'CheckBox'); $i = 0; foreach ($elementTypes as $elementType) { - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[$i]); + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$elementType}", $elementCollection[$i]); $i++; } $this->assertInstanceOf("PhpOffice\\PhpWord\\TOC", $elementCollection[$i]); @@ -106,7 +106,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase /** * Test add object exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidObjectException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testAddObjectException() { @@ -125,7 +125,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section->addTitle('Test', 1); $elementCollection = $section->getElements(); - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\Title", $elementCollection[0]); + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\Title", $elementCollection[0]); } /** @@ -138,7 +138,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase foreach ($elements as $element) { $method = "create{$element}"; - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$element}", $object->$method()); + $this->assertInstanceOf("PhpOffice\\PhpWord\\Container\\{$element}", $object->$method()); } $this->assertFalse($object->hasDifferentFirstPage()); } diff --git a/tests/PhpWord/Tests/Section/SettingsTest.php b/tests/PhpWord/Tests/Container/SettingsTest.php similarity index 95% rename from tests/PhpWord/Tests/Section/SettingsTest.php rename to tests/PhpWord/Tests/Container/SettingsTest.php index 8fb62f1c..3d5ae43a 100644 --- a/tests/PhpWord/Tests/Section/SettingsTest.php +++ b/tests/PhpWord/Tests/Container/SettingsTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Container; -use PhpOffice\PhpWord\Section\Settings; +use PhpOffice\PhpWord\Container\Settings; /** - * Test class for PhpOffice\PhpWord\Section\Settings + * Test class for PhpOffice\PhpWord\Container\Settings * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Settings + * @coversDefaultClass \PhpOffice\PhpWord\Container\Settings * @runTestsInSeparateProcesses */ class SettingsTest extends \PHPUnit_Framework_TestCase @@ -255,10 +255,10 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getColsSpace()); $iVal = rand(1, 1000); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Settings', $oSettings->setColsSpace($iVal)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Settings', $oSettings->setColsSpace($iVal)); $this->assertEquals($iVal, $oSettings->getColsSpace()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Settings', $oSettings->setColsSpace()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Settings', $oSettings->setColsSpace()); $this->assertEquals(720, $oSettings->getColsSpace()); } diff --git a/tests/PhpWord/Tests/Section/CheckBoxTest.php b/tests/PhpWord/Tests/Element/CheckBoxTest.php similarity index 91% rename from tests/PhpWord/Tests/Section/CheckBoxTest.php rename to tests/PhpWord/Tests/Element/CheckBoxTest.php index d07a0b69..e4611618 100644 --- a/tests/PhpWord/Tests/Section/CheckBoxTest.php +++ b/tests/PhpWord/Tests/Element/CheckBoxTest.php @@ -7,13 +7,13 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\CheckBox; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Style\Font; /** - * Test class for PhpOffice\PhpWord\Section\CheckBox + * Test class for PhpOffice\PhpWord\Element\CheckBox * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class CheckBoxTest extends \PHPUnit_Framework_TestCase { $oCheckBox = new CheckBox(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\CheckBox', $oCheckBox); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $oCheckBox); $this->assertEquals(null, $oCheckBox->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Section/FootnoteTest.php b/tests/PhpWord/Tests/Element/FootnoteTest.php similarity index 87% rename from tests/PhpWord/Tests/Section/FootnoteTest.php rename to tests/PhpWord/Tests/Element/FootnoteTest.php index fc537ab8..21a18a4f 100644 --- a/tests/PhpWord/Tests/Section/FootnoteTest.php +++ b/tests/PhpWord/Tests/Element/FootnoteTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Footnote; +use PhpOffice\PhpWord\Element\Footnote; /** - * Test class for PhpOffice\PhpWord\Section\Footnote + * Test class for PhpOffice\PhpWord\Element\Footnote * * @runTestsInSeparateProcesses */ @@ -25,7 +25,7 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase { $oFootnote = new Footnote(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footnote', $oFootnote); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $oFootnote); $this->assertCount(0, $oFootnote->getElements()); $this->assertEquals($oFootnote->getParagraphStyle(), null); } @@ -62,7 +62,7 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $element = $oFootnote->addText('text'); $this->assertCount(1, $oFootnote->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } /** @@ -85,7 +85,7 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $element = $oFootnote->addLink('http://www.google.fr'); $this->assertCount(1, $oFootnote->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); } /** diff --git a/tests/PhpWord/Tests/Section/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php similarity index 89% rename from tests/PhpWord/Tests/Section/ImageTest.php rename to tests/PhpWord/Tests/Element/ImageTest.php index bd4bf394..b0c3d88c 100644 --- a/tests/PhpWord/Tests/Section/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Element\Image; /** - * Test class for PhpOffice\PhpWord\Section\Image + * Test class for PhpOffice\PhpWord\Element\Image * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/images/firefox.png"; $oImage = new Image($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); $this->assertEquals($oImage->getMediaId(), md5($src)); $this->assertEquals($oImage->getIsWatermark(), false); @@ -64,7 +64,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase /** * Image not found * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidImageException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testImageNotFound() { @@ -74,7 +74,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase /** * Invalid image types * - * @expectedException \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException + * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function testInvalidImageTypes() { @@ -123,7 +123,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/images/firefox.png"; $oImage = new Image($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); $this->assertEquals($oImage->getMediaId(), md5($src)); $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefrompng'); @@ -140,7 +140,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/images/mario.gif"; $oImage = new Image($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); $this->assertEquals($oImage->getMediaId(), md5($src)); $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromgif'); @@ -157,7 +157,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/images/earth.jpg"; $oImage = new Image($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); $this->assertEquals($oImage->getMediaId(), md5($src)); $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromjpeg'); @@ -173,7 +173,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase { $oImage = new Image(__DIR__ . "/../_files/images/duke_nukem.bmp"); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getImageCreateFunction(), null); $this->assertEquals($oImage->getImageFunction(), null); $this->assertEquals($oImage->getImageExtension(), 'bmp'); @@ -187,7 +187,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase { $oImage = new Image(__DIR__ . "/../_files/images/angela_merkel.tif"); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getImageCreateFunction(), null); $this->assertEquals($oImage->getImageFunction(), null); $this->assertEquals($oImage->getImageType(), 'image/tiff'); diff --git a/tests/PhpWord/Tests/Section/LinkTest.php b/tests/PhpWord/Tests/Element/LinkTest.php similarity index 87% rename from tests/PhpWord/Tests/Section/LinkTest.php rename to tests/PhpWord/Tests/Element/LinkTest.php index ae1a3e09..9f89b21c 100644 --- a/tests/PhpWord/Tests/Section/LinkTest.php +++ b/tests/PhpWord/Tests/Element/LinkTest.php @@ -7,15 +7,15 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Link; +use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Style\Font; /** - * Test class for PhpOffice\PhpWord\Section\Link + * Test class for PhpOffice\PhpWord\Element\Link * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Link + * @coversDefaultClass \PhpOffice\PhpWord\Element\Link * @runTestsInSeparateProcesses */ class LinkTest extends \PHPUnit_Framework_TestCase @@ -27,7 +27,7 @@ class LinkTest extends \PHPUnit_Framework_TestCase { $oLink = new Link('http://www.google.com'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $oLink); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); $this->assertEquals($oLink->getLinkSrc(), 'http://www.google.com'); $this->assertEquals($oLink->getLinkName(), null); $this->assertEquals($oLink->getFontStyle(), null); @@ -46,7 +46,7 @@ class LinkTest extends \PHPUnit_Framework_TestCase array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $oLink); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); $this->assertEquals($oLink->getLinkSrc(), 'http://www.google.com'); $this->assertEquals($oLink->getLinkName(), 'Search Engine'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); diff --git a/tests/PhpWord/Tests/Section/ListItemTest.php b/tests/PhpWord/Tests/Element/ListItemTest.php similarity index 81% rename from tests/PhpWord/Tests/Section/ListItemTest.php rename to tests/PhpWord/Tests/Element/ListItemTest.php index 1964cdac..6526f571 100644 --- a/tests/PhpWord/Tests/Section/ListItemTest.php +++ b/tests/PhpWord/Tests/Element/ListItemTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\ListItem; +use PhpOffice\PhpWord\Element\ListItem; /** - * Test class for PhpOffice\PhpWord\Section\ListItem + * Test class for PhpOffice\PhpWord\Element\ListItem * - * @coversDefaultClass \PhpOffice\PhpWord\Section\ListItem + * @coversDefaultClass \PhpOffice\PhpWord\Element\ListItem * @runTestsInSeparateProcesses */ class ListItemTest extends \PHPUnit_Framework_TestCase @@ -26,7 +26,7 @@ class ListItemTest extends \PHPUnit_Framework_TestCase { $oListItem = new ListItem('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $oListItem->getTextObject()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject()); } /** diff --git a/tests/PhpWord/Tests/Section/ObjectTest.php b/tests/PhpWord/Tests/Element/ObjectTest.php similarity index 86% rename from tests/PhpWord/Tests/Section/ObjectTest.php rename to tests/PhpWord/Tests/Element/ObjectTest.php index d6094de1..22b4787f 100644 --- a/tests/PhpWord/Tests/Section/ObjectTest.php +++ b/tests/PhpWord/Tests/Element/ObjectTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Object; +use PhpOffice\PhpWord\Element\Object; /** - * Test class for PhpOffice\PhpWord\Section\Object + * Test class for PhpOffice\PhpWord\Element\Object * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Object + * @coversDefaultClass \PhpOffice\PhpWord\Element\Object * @runTestsInSeparateProcesses */ class ObjectTest extends \PHPUnit_Framework_TestCase @@ -27,7 +27,7 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/documents/sheet.xls"; $oObject = new Object($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($oObject->getSource(), $src); } @@ -40,7 +40,7 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; $oObject = new Object($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertEquals($oObject->getSource(), null); $this->assertEquals($oObject->getStyle(), null); } @@ -53,7 +53,7 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $src = __DIR__ . "/../_files/documents/sheet.xls"; $oObject = new Object($src, array('width' => '230px')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($oObject->getSource(), $src); } diff --git a/tests/PhpWord/Tests/Section/PageBreakTest.php b/tests/PhpWord/Tests/Element/PageBreakTest.php similarity index 65% rename from tests/PhpWord/Tests/Section/PageBreakTest.php rename to tests/PhpWord/Tests/Element/PageBreakTest.php index bf8b03a3..3dbaad87 100644 --- a/tests/PhpWord/Tests/Section/PageBreakTest.php +++ b/tests/PhpWord/Tests/Element/PageBreakTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\PageBreak; +use PhpOffice\PhpWord\Element\PageBreak; /** - * Test class for PhpOffice\PhpWord\Section\PageBreak + * Test class for PhpOffice\PhpWord\Element\PageBreak * - * @coversDefaultClass \PhpOffice\PhpWord\Section\PageBreak + * @coversDefaultClass \PhpOffice\PhpWord\Element\PageBreak * @runTestsInSeparateProcesses */ class PageBreakTest extends \PHPUnit_Framework_TestCase @@ -27,6 +27,6 @@ class PageBreakTest extends \PHPUnit_Framework_TestCase // Section Settings $oPageBreak = new PageBreak(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\PageBreak', $oPageBreak); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PageBreak', $oPageBreak); } } diff --git a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php similarity index 85% rename from tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php rename to tests/PhpWord/Tests/Element/PreserveTextTest.php index 82ded881..16d4361d 100644 --- a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section\Footer; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Footer\PreserveText; +use PhpOffice\PhpWord\Element\PreserveText; /** - * Test class for PhpOffice\PhpWord\Section\Footer\PreserveText + * Test class for PhpOffice\PhpWord\Element\PreserveText * * @runTestsInSeparateProcesses */ @@ -25,7 +25,7 @@ class PreserveTextTest extends \PHPUnit_Framework_TestCase { $oPreserveText = new PreserveText(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $oPreserveText); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $oPreserveText); $this->assertEquals($oPreserveText->getText(), null); $this->assertEquals($oPreserveText->getFontStyle(), null); $this->assertEquals($oPreserveText->getParagraphStyle(), null); diff --git a/tests/PhpWord/Tests/Section/Table/CellTest.php b/tests/PhpWord/Tests/Element/Table/CellTest.php similarity index 82% rename from tests/PhpWord/Tests/Section/Table/CellTest.php rename to tests/PhpWord/Tests/Element/Table/CellTest.php index 6f38d986..661120d4 100644 --- a/tests/PhpWord/Tests/Section/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/Table/CellTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section\Table; +namespace PhpOffice\PhpWord\Tests\Element\Table; -use PhpOffice\PhpWord\Section\Table\Cell; +use PhpOffice\PhpWord\Element\Table\Cell; /** - * Test class for PhpOffice\PhpWord\Section\Table\Cell + * Test class for PhpOffice\PhpWord\Element\Table\Cell * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oCell = new Cell('section', $iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $oCell); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $oCell); $this->assertEquals($oCell->getWidth(), null); } @@ -62,7 +62,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addText('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } /** @@ -74,7 +74,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertEquals($element->getText(), 'ééé'); } @@ -87,12 +87,12 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); } /** * Add link exception - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testAddLinkException() { @@ -120,7 +120,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addListItem('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\ListItem', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); $this->assertEquals($element->getTextObject()->getText(), 'text'); } @@ -133,7 +133,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addListItem(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\ListItem', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); $this->assertEquals($element->getTextObject()->getText(), 'ééé'); } @@ -148,7 +148,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element2 = $oCell->addMemoryImage($src); // @deprecated $this->assertCount(2, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element1); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); } /** @@ -161,7 +161,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -174,7 +174,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -188,7 +188,7 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -202,7 +202,7 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -216,7 +216,7 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** @@ -229,13 +229,13 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addObject($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $element); } /** * Test add object exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidObjectException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException */ public function testAddObjectException() { @@ -253,7 +253,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addPreserveText('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } /** @@ -265,14 +265,14 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } /** * Add preserve text exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testAddPreserveTextException() { @@ -289,7 +289,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->createTextRun(); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); } /** @@ -301,7 +301,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\CheckBox', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); } /** diff --git a/tests/PhpWord/Tests/Section/Table/RowTest.php b/tests/PhpWord/Tests/Element/Table/RowTest.php similarity index 81% rename from tests/PhpWord/Tests/Section/Table/RowTest.php rename to tests/PhpWord/Tests/Element/Table/RowTest.php index 10d53915..f64c0cb4 100644 --- a/tests/PhpWord/Tests/Section/Table/RowTest.php +++ b/tests/PhpWord/Tests/Element/Table/RowTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section\Table; +namespace PhpOffice\PhpWord\Tests\Element\Table; -use PhpOffice\PhpWord\Section\Table\Row; +use PhpOffice\PhpWord\Element\Table\Row; /** - * Test class for PhpOffice\PhpWord\Section\Table\Row + * Test class for PhpOffice\PhpWord\Element\Table\Row * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Table\Row + * @coversDefaultClass \PhpOffice\PhpWord\Element\Table\Row * @runTestsInSeparateProcesses */ class RowTest extends \PHPUnit_Framework_TestCase @@ -27,7 +27,7 @@ class RowTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oRow = new Row('section', $iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Row', $oRow); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Row', $oRow); $this->assertEquals($oRow->getHeight(), null); $this->assertInternalType('array', $oRow->getCells()); $this->assertCount(0, $oRow->getCells()); @@ -60,7 +60,7 @@ class RowTest extends \PHPUnit_Framework_TestCase $oRow = new Row('section', 1); $element = $oRow->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $element); $this->assertCount(1, $oRow->getCells()); } } diff --git a/tests/PhpWord/Tests/Section/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php similarity index 83% rename from tests/PhpWord/Tests/Section/TableTest.php rename to tests/PhpWord/Tests/Element/TableTest.php index 9808485d..1b337fd6 100644 --- a/tests/PhpWord/Tests/Section/TableTest.php +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Table; +use PhpOffice\PhpWord\Element\Table; /** - * Test class for PhpOffice\PhpWord\Section\Table + * Test class for PhpOffice\PhpWord\Element\Table * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Table + * @coversDefaultClass \PhpOffice\PhpWord\Element\Table * @runTestsInSeparateProcesses */ class TableTest extends \PHPUnit_Framework_TestCase @@ -26,7 +26,7 @@ class TableTest extends \PHPUnit_Framework_TestCase { $oTable = new Table('section', 1); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $oTable); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $oTable); $this->assertEquals($oTable->getStyle(), null); $this->assertEquals($oTable->getWidth(), null); $this->assertEquals($oTable->getRows(), array()); @@ -75,7 +75,7 @@ class TableTest extends \PHPUnit_Framework_TestCase { $oTable = new Table('section', 1); $element = $oTable->addRow(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Row', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Row', $element); $this->assertCount(1, $oTable->getRows()); } @@ -87,6 +87,6 @@ class TableTest extends \PHPUnit_Framework_TestCase $oTable = new Table('section', 1); $oTable->addRow(); $element = $oTable->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $element); } } diff --git a/tests/PhpWord/Tests/Section/TextBreakTest.php b/tests/PhpWord/Tests/Element/TextBreakTest.php similarity index 89% rename from tests/PhpWord/Tests/Section/TextBreakTest.php rename to tests/PhpWord/Tests/Element/TextBreakTest.php index cf7a58c4..c228215f 100644 --- a/tests/PhpWord/Tests/Section/TextBreakTest.php +++ b/tests/PhpWord/Tests/Element/TextBreakTest.php @@ -7,16 +7,16 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\TextBreak; +use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; /** - * Test class for PhpOffice\PhpWord\Section\TextBreak + * Test class for PhpOffice\PhpWord\Element\TextBreak * - * @coversDefaultClass \PhpOffice\PhpWord\Section\TextBreak + * @coversDefaultClass \PhpOffice\PhpWord\Element\TextBreak * @runTestsInSeparateProcesses */ class TextBreakTest extends \PHPUnit_Framework_TestCase diff --git a/tests/PhpWord/Tests/Section/TextRunTest.php b/tests/PhpWord/Tests/Element/TextRunTest.php similarity index 82% rename from tests/PhpWord/Tests/Section/TextRunTest.php rename to tests/PhpWord/Tests/Element/TextRunTest.php index 32b6d4dc..e71ce108 100644 --- a/tests/PhpWord/Tests/Section/TextRunTest.php +++ b/tests/PhpWord/Tests/Element/TextRunTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\TextRun; +use PhpOffice\PhpWord\Element\TextRun; /** - * Test class for PhpOffice\PhpWord\Section\TextRun + * Test class for PhpOffice\PhpWord\Element\TextRun * * @runTestsInSeparateProcesses */ @@ -25,7 +25,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase { $oTextRun = new TextRun(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertEquals($oTextRun->getParagraphStyle(), null); } @@ -37,7 +37,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase { $oTextRun = new TextRun('pStyle'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertEquals($oTextRun->getParagraphStyle(), 'pStyle'); } @@ -49,7 +49,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase { $oTextRun = new TextRun(array('spacing' => 100)); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } @@ -62,7 +62,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addText('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getText(), 'text'); } @@ -75,7 +75,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addText(utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getText(), 'ééé'); } @@ -88,7 +88,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addLink('http://www.google.fr'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getLinkSrc(), 'http://www.google.fr'); } @@ -101,7 +101,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addLink('http://www.google.fr', utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getLinkSrc(), 'http://www.google.fr'); $this->assertEquals($element->getLinkName(), 'ééé'); @@ -128,7 +128,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addImage($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); $this->assertCount(1, $oTextRun->getElements()); } @@ -140,7 +140,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->createFootnote(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footnote', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $element); $this->assertCount(1, $oTextRun->getElements()); } } diff --git a/tests/PhpWord/Tests/Section/TextTest.php b/tests/PhpWord/Tests/Element/TextTest.php similarity index 90% rename from tests/PhpWord/Tests/Section/TextTest.php rename to tests/PhpWord/Tests/Element/TextTest.php index 5811c735..953dfc8f 100644 --- a/tests/PhpWord/Tests/Section/TextTest.php +++ b/tests/PhpWord/Tests/Element/TextTest.php @@ -7,13 +7,13 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Text; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Style\Font; /** - * Test class for PhpOffice\PhpWord\Section\Text + * Test class for PhpOffice\PhpWord\Element\Text * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class TextTest extends \PHPUnit_Framework_TestCase { $oText = new Text(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $oText); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oText); $this->assertEquals(null, $oText->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); diff --git a/tests/PhpWord/Tests/Section/TitleTest.php b/tests/PhpWord/Tests/Element/TitleTest.php similarity index 84% rename from tests/PhpWord/Tests/Section/TitleTest.php rename to tests/PhpWord/Tests/Element/TitleTest.php index a63d184c..6c472b0d 100644 --- a/tests/PhpWord/Tests/Section/TitleTest.php +++ b/tests/PhpWord/Tests/Element/TitleTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Section; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Section\Title; +use PhpOffice\PhpWord\Element\Title; /** - * Test class for PhpOffice\PhpWord\Section\Title + * Test class for PhpOffice\PhpWord\Element\Title * - * @coversDefaultClass \PhpOffice\PhpWord\Section\Title + * @coversDefaultClass \PhpOffice\PhpWord\Element\Title * @runTestsInSeparateProcesses */ class TitleTest extends \PHPUnit_Framework_TestCase @@ -26,7 +26,7 @@ class TitleTest extends \PHPUnit_Framework_TestCase { $oTitle = new Title('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Title', $oTitle); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle); $this->assertEquals($oTitle->getText(), 'text'); } diff --git a/tests/PhpWord/Tests/Exceptions/ExceptionTest.php b/tests/PhpWord/Tests/Exception/ExceptionTest.php similarity index 55% rename from tests/PhpWord/Tests/Exceptions/ExceptionTest.php rename to tests/PhpWord/Tests/Exception/ExceptionTest.php index 81732c97..04eb03e0 100644 --- a/tests/PhpWord/Tests/Exceptions/ExceptionTest.php +++ b/tests/PhpWord/Tests/Exception/ExceptionTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Exceptions; +namespace PhpOffice\PhpWord\Tests\Exception; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** - * Test class for PhpOffice\PhpWord\Exceptions\Exception + * Test class for PhpOffice\PhpWord\Exception\Exception * - * @coversDefaultClass \PhpOffice\PhpWord\Exceptions\Exception + * @coversDefaultClass \PhpOffice\PhpWord\Exception\Exception * @runTestsInSeparateProcesses */ class ExceptionTest extends \PHPUnit_Framework_TestCase @@ -22,8 +22,8 @@ class ExceptionTest extends \PHPUnit_Framework_TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception - * @covers \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @covers \PhpOffice\PhpWord\Exception\Exception */ public function testThrowException() { diff --git a/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php b/tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php similarity index 52% rename from tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php rename to tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php index 7db70993..c0dfedda 100644 --- a/tests/PhpWord/Tests/Exceptions/InvalidImageExceptionTest.php +++ b/tests/PhpWord/Tests/Exception/InvalidImageExceptionTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Exceptions; +namespace PhpOffice\PhpWord\Tests\Exception; -use PhpOffice\PhpWord\Exceptions\InvalidImageException; +use PhpOffice\PhpWord\Exception\InvalidImageException; /** - * Test class for PhpOffice\PhpWord\Exceptions\InvalidImageException + * Test class for PhpOffice\PhpWord\Exception\InvalidImageException * - * @coversDefaultClass \PhpOffice\PhpWord\Exceptions\InvalidImageException + * @coversDefaultClass \PhpOffice\PhpWord\Exception\InvalidImageException * @runTestsInSeparateProcesses */ class InvalidImageExceptionTest extends \PHPUnit_Framework_TestCase @@ -22,8 +22,8 @@ class InvalidImageExceptionTest extends \PHPUnit_Framework_TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidImageException - * @covers \PhpOffice\PhpWord\Exceptions\InvalidImageException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + * @covers \PhpOffice\PhpWord\Exception\InvalidImageException */ public function testThrowException() { diff --git a/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php b/tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php similarity index 52% rename from tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php rename to tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php index 174e07ac..1cc29a72 100644 --- a/tests/PhpWord/Tests/Exceptions/InvalidStyleExceptionTest.php +++ b/tests/PhpWord/Tests/Exception/InvalidStyleExceptionTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Exceptions; +namespace PhpOffice\PhpWord\Tests\Exception; -use PhpOffice\PhpWord\Exceptions\InvalidStyleException; +use PhpOffice\PhpWord\Exception\InvalidStyleException; /** - * Test class for PhpOffice\PhpWord\Exceptions\InvalidStyleException + * Test class for PhpOffice\PhpWord\Exception\InvalidStyleException * - * @coversDefaultClass \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @coversDefaultClass \PhpOffice\PhpWord\Exception\InvalidStyleException * @runTestsInSeparateProcesses */ class InvalidStyleExceptionTest extends \PHPUnit_Framework_TestCase @@ -22,8 +22,8 @@ class InvalidStyleExceptionTest extends \PHPUnit_Framework_TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException - * @covers \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException + * @covers \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testThrowException() { diff --git a/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php b/tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php similarity index 50% rename from tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php rename to tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php index 027ec3a9..a73db599 100644 --- a/tests/PhpWord/Tests/Exceptions/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWord/Tests/Exception/UnsupportedImageTypeExceptionTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Exceptions; +namespace PhpOffice\PhpWord\Tests\Exception; -use PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException; +use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; /** - * Test class for PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeExceptionTest + * Test class for PhpOffice\PhpWord\Exception\UnsupportedImageTypeExceptionTest * - * @coversDefaultClass \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeExceptionTest + * @coversDefaultClass \PhpOffice\PhpWord\Exception\UnsupportedImageTypeExceptionTest * @runTestsInSeparateProcesses */ class UnsupportedImageTypeExceptionTest extends \PHPUnit_Framework_TestCase @@ -22,8 +22,8 @@ class UnsupportedImageTypeExceptionTest extends \PHPUnit_Framework_TestCase /** * Throw new exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException - * @covers \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException + * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException + * @covers \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ public function testThrowException() { diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index 79bb75ad..5ea7ed80 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -23,7 +23,7 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase */ public function testFootnote() { - $footnoteElement = new \PhpOffice\PhpWord\Section\Footnote(); + $footnoteElement = new \PhpOffice\PhpWord\Element\Footnote(); $rIdFootnote = Footnote::addFootnoteElement($footnoteElement); $rIdLink = Footnote::addFootnoteLinkElement('http://test.com'); diff --git a/tests/PhpWord/Tests/IOFactoryTest.php b/tests/PhpWord/Tests/IOFactoryTest.php index bb2a6530..405eabe0 100644 --- a/tests/PhpWord/Tests/IOFactoryTest.php +++ b/tests/PhpWord/Tests/IOFactoryTest.php @@ -33,7 +33,7 @@ class IOFactoryTest extends \PHPUnit_Framework_TestCase /** * Create non-existing writer * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testNonexistentWriterCanNotBeCreated() { @@ -54,7 +54,7 @@ class IOFactoryTest extends \PHPUnit_Framework_TestCase /** * Create non-existing reader * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testNonexistentReaderCanNotBeCreated() { diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 62ce56a9..852cedb7 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -10,8 +10,8 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Section; -use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Image; /** * Test class for PhpOffice\PhpWord\Media diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 500d46c8..2cf5ae62 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -11,7 +11,7 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Container\Section; use PhpOffice\PhpWord\Style; /** @@ -140,7 +140,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase /** * Test load template exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testLoadTemplateException() { diff --git a/tests/PhpWord/Tests/Reader/Word2007Test.php b/tests/PhpWord/Tests/Reader/Word2007Test.php index 5aee8144..3a572f4d 100644 --- a/tests/PhpWord/Tests/Reader/Word2007Test.php +++ b/tests/PhpWord/Tests/Reader/Word2007Test.php @@ -43,7 +43,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase /** * Can read exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testCanReadFailed() { diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index ed4d61db..47ed57f4 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -144,7 +144,7 @@ class FontTest extends \PHPUnit_Framework_TestCase /** * Test line height exception by using nonnumeric value * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testLineHeightException() { diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 619d5497..4c424a93 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -146,7 +146,7 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase /** * Test line height exception by using nonnumeric value * - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function testLineHeightException() { diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index 669ae946..eb766772 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -95,7 +95,7 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase * XSL stylesheet cannot be applied on failure in setting parameter value * * @covers ::applyXslStyleSheet - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage Could not set values for the given XSL style sheet parameters. * @test */ @@ -117,7 +117,7 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase * XSL stylesheet can be applied on failure of loading XML from template * * @covers ::applyXslStyleSheet - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage Could not load XML from the given template. * @test */ diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 8c345f55..9ee31432 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -44,7 +44,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase /** * Construct with null * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() @@ -105,7 +105,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase /** * Save with no PhpWord object assigned * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage PhpWord object unassigned. */ public function testSaveException() @@ -137,7 +137,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase /** * Use disk caching exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 7b546438..4016cb85 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -32,7 +32,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase /** * Construct with null * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() @@ -94,7 +94,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase /** * Save with no PhpWord object assigned * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage PhpWord object unassigned. */ public function testSaveException() diff --git a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php index 6d303a0a..c0f94de6 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php @@ -28,7 +28,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase public function testWriteFooter() { $imageSrc = __DIR__ . "/../../_files/images/PhpWord.png"; - $container = new \PhpOffice\PhpWord\Section\Footer(1); + $container = new \PhpOffice\PhpWord\Container\Footer(1); $container->addText(''); $container->addPreserveText(''); $container->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php index de3ac010..253f663e 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php @@ -26,7 +26,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $imageSrc = __DIR__ . "/../../_files/images/PhpWord.png"; - $container = new \PhpOffice\PhpWord\Section\Header(1); + $container = new \PhpOffice\PhpWord\Container\Header(1); $container->addText('Test'); $container->addPreserveText(''); $container->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index fa4e301c..f486d18d 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -115,7 +115,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase /** * Save with no PhpWord object assigned * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage PhpWord object unassigned. */ public function testSaveException() @@ -181,7 +181,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase /** * Use disk caching exception * - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { From b7fd62312151011bd0383c0e6e2e1df67eaecd78 Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 31 Mar 2014 17:07:58 +0200 Subject: [PATCH 035/146] Re-indent with spaces TOC Depth filter Travis said spaces, not tab. Meh. --- src/PhpWord/TOC.php | 90 ++++++++++++------------ src/PhpWord/Writer/Word2007/Document.php | 6 +- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index ef5ddba0..a17fb7f1 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -67,19 +67,19 @@ class TOC */ private static $_bookmarkId = 0; - /** - * Min title depth to show - * - * @var int - */ - private $_minDepth = 1; - - /** - * Max title depth to show - * - * @var int - */ - private $_maxDepth = 9; + /** + * Min title depth to show + * + * @var int + */ + private $_minDepth = 1; + + /** + * Max title depth to show + * + * @var int + */ + private $_maxDepth = 9; /** * Create a new Table-of-Contents Element @@ -114,9 +114,9 @@ class TOC self::$_styleFont = $styleFont; } } - - $this->_minDepth = $minDepth; - $this->_maxDepth = $maxDepth; + + $this->_minDepth = $minDepth; + $this->_maxDepth = $maxDepth; } /** @@ -150,17 +150,17 @@ class TOC public function getTitles() { $titles = self::$_titles; - foreach ($titles as $i=>$title) { - if ($this->_minDepth > $title['depth']) { - unset($titles[$i]); - } - if (($this->_maxDepth != 0) && ($this->_maxDepth < $title['depth'])) { - unset($titles[$i]); - } - } - $titles = array_merge(array(), $titles); - - return $titles; + foreach ($titles as $i => $title) { + if ($this->_minDepth > $title['depth']) { + unset($titles[$i]); + } + if (($this->_maxDepth != 0) && ($this->_maxDepth < $title['depth'])) { + unset($titles[$i]); + } + } + $titles = array_merge(array(), $titles); + + return $titles; } /** @@ -182,22 +182,22 @@ class TOC { return self::$_styleFont; } - - /** - * Get Max Depth - * - * @return int Max depth of titles - */ - public function getMaxDepth() { - return $this->_maxDepth; - } - - /** - * Get Min Depth - * - * @return int Min depth of titles - */ - public function getMinDepth() { - return $this->_minDepth; - } + + /** + * Get Max Depth + * + * @return int Max depth of titles + */ + public function getMaxDepth() { + return $this->_maxDepth; + } + + /** + * Get Min Depth + * + * @return int Min depth of titles + */ + public function getMinDepth() { + return $this->_minDepth; + } } diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 22cc8c0d..3ccc5f48 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -428,9 +428,9 @@ class Document extends Base $fIndent = $styleTOC->getIndent(); $tabLeader = $styleTOC->getTabLeader(); $tabPos = $styleTOC->getTabPos(); - - $maxDepth = $toc->getMaxDepth(); - $minDepth = $toc->getMinDepth(); + + $maxDepth = $toc->getMaxDepth(); + $minDepth = $toc->getMinDepth(); $isObject = ($styleFont instanceof Font) ? true : false; From 2bf0bbb094670e301e7b3ae2e0c0720f5b93e5e6 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 31 Mar 2014 23:10:51 +0700 Subject: [PATCH 036/146] Container abstract class --- CHANGELOG.md | 1 + src/PhpWord/Container/Container.php | 437 ++++++++++++++++++ src/PhpWord/Container/Footer.php | 185 +------- src/PhpWord/Container/Header.php | 232 +--------- src/PhpWord/Container/Section.php | 388 +++------------- src/PhpWord/Writer/Word2007.php | 2 +- tests/PhpWord/Tests/Container/FooterTest.php | 2 +- tests/PhpWord/Tests/Container/HeaderTest.php | 2 +- tests/PhpWord/Tests/Container/SectionTest.php | 8 +- 9 files changed, 537 insertions(+), 720 deletions(-) create mode 100644 src/PhpWord/Container/Container.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 63c295f0..c9c5d39a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 - Reader: Rename AbstractReader > Reader - @ivanlanin - General: Refactor folders: Element, Container, and Exception - @ivanlanin +- Container: Create new Container abstract class - @ivanlanin ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php new file mode 100644 index 00000000..7ca3ebb1 --- /dev/null +++ b/src/PhpWord/Container/Container.php @@ -0,0 +1,437 @@ +elements[] = $text; + + return $text; + } + + /** + * Add text break element + * + * @param int $count + * @param mixed $fontStyle + * @param mixed $paragraphStyle + */ + public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) + { + for ($i = 1; $i <= $count; $i++) { + $this->elements[] = new TextBreak($fontStyle, $paragraphStyle); + } + } + + /** + * Add textrun element + * + * @param mixed $styleParagraph + * @return TextRun + */ + public function addTextRun($styleParagraph = null) + { + $textRun = new TextRun($styleParagraph); + $this->elements[] = $textRun; + + return $textRun; + } + + /** + * Add link element + * + * @param string $linkSrc + * @param string $linkName + * @param mixed $styleFont + * @param mixed $styleParagraph + * @return Link + * @todo Enable link element in header and footer + */ + public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + if (!String::isUTF8($linkSrc)) { + $linkSrc = utf8_encode($linkSrc); + } + if (!is_null($linkName)) { + if (!String::isUTF8($linkName)) { + $linkName = utf8_encode($linkName); + } + } + $link = new Link($linkSrc, $linkName, $styleFont, $styleParagraph); + $rID = Media::addSectionLinkElement($linkSrc); + $link->setRelationId($rID); + $this->elements[] = $link; + return $link; + } + + /** + * Add a Title Element + * + * @param string $text + * @param int $depth + * @return Title + * @todo Enable title element in header and footer + */ + public function addTitle($text, $depth = 1) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + if (!String::isUTF8($text)) { + $text = utf8_encode($text); + } + $styles = Style::getStyles(); + if (array_key_exists('Heading_' . $depth, $styles)) { + $style = 'Heading' . $depth; + } else { + $style = null; + } + $title = new Title($text, $depth, $style); + $data = TOC::addTitle($text, $depth); + $anchor = $data[0]; + $bookmarkId = $data[1]; + $title->setAnchor($anchor); + $title->setBookmarkId($bookmarkId); + $this->elements[] = $title; + return $title; + } + + /** + * Add preserve text element + * + * @param string $text + * @param mixed $styleFont + * @param mixed $styleParagraph + * @return PreserveText + */ + public function addPreserveText($text, $styleFont = null, $styleParagraph = null) + { + if ($this->containerType == 'section') { + throw new \BadMethodCallException(); + } + + if (!String::isUTF8($text)) { + $text = utf8_encode($text); + } + $ptext = new PreserveText($text, $styleFont, $styleParagraph); + $this->elements[] = $ptext; + + return $ptext; + } + + /** + * Add listitem element + * + * @param string $text + * @param int $depth + * @param mixed $styleFont + * @param mixed $styleList + * @param mixed $styleParagraph + * @return ListItem + * @todo Enable list item element in header and footer + */ + public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + if (!String::isUTF8($text)) { + $text = utf8_encode($text); + } + $listItem = new ListItem($text, $depth, $styleFont, $styleList, $styleParagraph); + $this->elements[] = $listItem; + return $listItem; + } + + /** + * Add table element + * + * @param mixed $style + * @return Table + */ + public function addTable($style = null) + { + $table = new Table($this->containerType, $this->sectionId, $style); + $this->elements[] = $table; + + return $table; + } + + /** + * Add image element + * + * @param string $src + * @param mixed $style Image style + * @param boolean $isWatermark + * @return Image + */ + public function addImage($src, $style = null, $isWatermark = false) + { + $image = new Image($src, $style, $isWatermark); + if (!is_null($image->getSource())) { + switch ($this->containerType) { + case 'section': + $rID = Media::addSectionMediaElement($src, 'image', $image); + break; + case 'header': + $rID = Media::addHeaderMediaElement($this->sectionId, $src, $image); + break; + case 'footer': + $rID = Media::addFooterMediaElement($this->sectionId, $src, $image); + break; + } + $image->setRelationId($rID); + $this->elements[] = $image; + return $image; + } else { + throw new InvalidImageException; + } + } + + /** + * Add OLE-object element + * + * All exceptions should be handled by PhpOffice\PhpWord\Element\Object + * + * @param string $src + * @param mixed $style + * @return Object + * @todo Enable OLE object element in header and footer + */ + public function addObject($src, $style = null) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + $object = new Object($src, $style); + if (!is_null($object->getSource())) { + $inf = pathinfo($src); + $ext = $inf['extension']; + if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { + $ext = substr($ext, 0, -1); + } + $icon = __DIR__ . "/../_staticDocParts/_{$ext}.png"; + $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); + $data = Media::addSectionMediaElement($src, 'oleObject'); + $rID = $data[0]; + $objectId = $data[1]; + $object->setRelationId($rID); + $object->setObjectId($objectId); + $object->setImageRelationId($rIDimg); + $this->elements[] = $object; + return $object; + } else { + throw new InvalidObjectException(); + } + } + + /** + * Add footnote element + * + * @param mixed $styleParagraph + * @return FootnoteElement + * @todo Enable footnote element in header and footer + */ + public function addFootnote($styleParagraph = null) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + $footnote = new FootnoteElement($styleParagraph); + $refID = Footnote::addFootnoteElement($footnote); + $footnote->setReferenceId($refID); + $this->elements[] = $footnote; + return $footnote; + } + + /** + * Add a CheckBox Element + * + * @param string $name + * @param string $text + * @param mixed $styleFont + * @param mixed $styleParagraph + * @return CheckBox + * @todo Enable checkbox element in header and footer + */ + public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) + { + if ($this->containerType != 'section') { + throw new \BadMethodCallException(); + } + + if (!String::isUTF8($name)) { + $name = utf8_encode($name); + } + if (!String::isUTF8($text)) { + $text = utf8_encode($text); + } + $element = new CheckBox($name, $text, $styleFont, $styleParagraph); + $this->elements[] = $element; + + return $element; + } + + /** + * Get section number + * getFooterCount + */ + public function getSectionId() + { + return $this->sectionId; + } + + /** + * Get all elements + * + * @return array + */ + public function getElements() + { + return $this->elements; + } + + /** + * Get relation Id + * + * @return int + */ + public function getRelationId() + { + if ($this->containerType == 'section') { + throw new \BadMethodCallException(); + } + + return $this->relationId; + } + + /** + * Set relation Id + * + * @param int $rId + */ + public function setRelationId($rId) + { + if ($this->containerType == 'section') { + throw new \BadMethodCallException(); + } + + $this->relationId = $rId; + } + + /** + * Add memory image element + * + * @param string $src + * @param mixed $style + * @deprecated 0.9.0 + */ + public function addMemoryImage($src, $style = null) + { + return $this->addImage($src, $style); + } + + /** + * Create textrun element + * + * @param mixed $styleParagraph + * @deprecated 0.9.2 + */ + public function createTextRun($styleParagraph = null) + { + return $this->addTextRun($styleParagraph); + } + + /** + * Create footnote element + * + * @param mixed $styleParagraph + * @deprecated 0.9.2 + */ + public function createFootnote($styleParagraph = null) + { + return $this->addFootnote($styleParagraph); + } +} diff --git a/src/PhpWord/Container/Footer.php b/src/PhpWord/Container/Footer.php index c1e6034e..37884b86 100755 --- a/src/PhpWord/Container/Footer.php +++ b/src/PhpWord/Container/Footer.php @@ -9,192 +9,19 @@ namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exception\InvalidImageException; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Image; - /** * Footer element */ -class Footer +class Footer extends Container { /** - * Footer Count + * Create new instance * - * @var int + * @param int $sectionId */ - private $_footerCount; - - /** - * Footer Relation ID - * - * @var int - */ - private $_rId; - - /** - * Footer Element Collection - * - * @var int - */ - private $_elementCollection = array(); - - /** - * Create a new Footer - * - * @param int $sectionCount - */ - public function __construct($sectionCount) + public function __construct($sectionId) { - $this->_footerCount = $sectionCount; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table - */ - public function addTable($style = null) - { - $table = new Table('footer', $this->_footerCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addFooterMediaElement($this->_footerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $src - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; - } - - /** - * Get Footer Relation ID - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Footer Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get all Footer Elements - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Footer Count - */ - public function getFooterCount() - { - return $this->_footerCount; + $this->containerType = 'footer'; + $this->sectionId = $sectionId; } } diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Container/Header.php index 5b6fce42..3c702406 100755 --- a/src/PhpWord/Container/Header.php +++ b/src/PhpWord/Container/Header.php @@ -9,187 +9,39 @@ namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exception\InvalidImageException; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Image; /** * Header element */ -class Header +class Header extends Container { /** - * Header Count + * Header types constants * - * @var int + * @var string + * @link http://www.schemacentral.com/sc/ooxml/a-wheaderType-4.html Header or Footer Type */ - private $_headerCount; - - /** - * Header Relation ID - * - * @var int - */ - private $_rId; + const AUTO = 'default'; // Did not use DEFAULT because it is a PHP keyword + const EVEN = 'even'; + const FIRST = 'first'; /** * Header type * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_type-4.html Header or Footer Type */ - private $_type = self::AUTO; + private $headerType = self::AUTO; /** - * Even Numbered Pages Only - * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_type-4.html Header or Footer Type - */ - const EVEN = 'even'; - - /** - * Default Header or Footer - * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_type-4.html Header or Footer Type - */ - const AUTO = 'default'; // Did not use DEFAULT because it is a PHP keyword - - /** - * First Page Only - * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-w_type-4.html Header or Footer Type - */ - const FIRST = 'first'; - - /** - * Header Element Collection - * - * @var int - */ - private $_elementCollection = array(); - - /** - * Create a new Header + * Create new instance * * @param int $sectionCount */ - public function __construct($sectionCount) + public function __construct($sectionId) { - $this->_headerCount = $sectionCount; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table - */ - public function addTable($style = null) - { - $table = new Table('header', $this->_headerCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addHeaderMediaElement($this->_headerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $src - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; + $this->containerType = 'header'; + $this->sectionId = $sectionId; } /** @@ -197,69 +49,27 @@ class Header * * @param string $src * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image + * @return Image */ public function addWatermark($src, $style = null) { - $image = new Image($src, $style, true); - if (!is_null($image->getSource())) { - $rID = Media::addHeaderMediaElement($this->_headerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } + return $this->addImage($src, $style, true); } /** - * Get Header Relation ID - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Header Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get all Header Elements - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Header Count - */ - public function getHeaderCount() - { - return $this->_headerCount; - } - - /** - * Get Header Type + * Get header type */ public function getType() { - return $this->_type; + return $this->headerType; } /** - * Reset back to default + * Reset type to default */ public function resetType() { - return $this->_type = self::AUTO; + return $this->headerType = self::AUTO; } /** @@ -267,14 +77,14 @@ class Header */ public function firstPage() { - return $this->_type = self::FIRST; + return $this->headerType = self::FIRST; } /** - * Even numbered Pages only + * Even numbered pages only */ public function evenPage() { - return $this->_type = self::EVEN; + return $this->headerType = self::EVEN; } } diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index a3002cb3..dcef4707 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -9,85 +9,57 @@ namespace PhpOffice\PhpWord\Container; -use PhpOffice\PhpWord\Exception\InvalidImageException; -use PhpOffice\PhpWord\Exception\InvalidObjectException; -use PhpOffice\PhpWord\Footnote; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\TOC; use PhpOffice\PhpWord\Container\Footer; use PhpOffice\PhpWord\Container\Header; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\Title; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Container\Settings; use PhpOffice\PhpWord\Element\PageBreak; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Object; -use PhpOffice\PhpWord\Element\CheckBox; -use PhpOffice\PhpWord\Shared\String; /** * Section */ -class Section +class Section extends Container { - /** - * Section count - * - * @var int - */ - private $_sectionCount; - /** * Section settings * - * @var \PhpOffice\PhpWord\Container\Settings + * @var Settings */ - private $_settings; + private $settings; /** - * Section Element Collection + * Section headers * - * @var array + * @var Header[] */ - private $_elementCollection = array(); + private $headers = array(); /** - * Section Headers + * Section footer * - * @var array + * @var Footer */ - private $_headers = array(); - - /** - * Section Footer - * - * @var \PhpOffice\PhpWord\Container\Footer - */ - private $_footer = null; + private $footer = null; /** - * Create a new Section + * Create new instance * * @param int $sectionCount * @param mixed $settings */ public function __construct($sectionCount, $settings = null) { - $this->_sectionCount = $sectionCount; - $this->_settings = new \PhpOffice\PhpWord\Container\Settings(); + $this->containerType = 'section'; + $this->sectionId = $sectionCount; + $this->settings = new Settings(); $this->setSettings($settings); } /** - * Set Section Settings + * Set section settings * - * @param array $settings + * @param array $settings */ public function setSettings($settings = null) { @@ -96,7 +68,7 @@ class Section if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - $this->_settings->setSettingValue($key, $value); + $this->settings->setSettingValue($key, $value); } } } @@ -104,71 +76,11 @@ class Section /** * Get Section Settings * - * @return \PhpOffice\PhpWord\Container\Settings + * @return Settings */ public function getSettings() { - return $this->_settings; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($linkSrc)) { - $linkSrc = utf8_encode($linkSrc); - } - if (!is_null($linkName)) { - if (!String::isUTF8($linkName)) { - $linkName = utf8_encode($linkName); - } - } - - $link = new Link($linkSrc, $linkName, $styleFont, $styleParagraph); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Add a TextBreak Element - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } + return $this->settings; } /** @@ -176,104 +88,7 @@ class Section */ public function addPageBreak() { - $this->_elementCollection[] = new PageBreak(); - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table - */ - public function addTable($style = null) - { - $table = new Table('section', $this->_sectionCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a ListItem Element - * - * @param string $text - * @param int $depth - * @param mixed $styleFont - * @param mixed $styleList - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\ListItem - */ - public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $listItem = new ListItem($text, $depth, $styleFont, $styleList, $styleParagraph); - $this->_elementCollection[] = $listItem; - return $listItem; - } - - /** - * Add a OLE-Object Element - * - * All exceptions should be handled by PhpOffice\PhpWord\Element\Object - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Object - */ - public function addObject($src, $style = null) - { - $object = new Object($src, $style); - if (!is_null($object->getSource())) { - $inf = pathinfo($src); - $ext = $inf['extension']; - if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { - $ext = substr($ext, 0, -1); - } - $icon = __DIR__ . "/../_staticDocParts/_{$ext}.png"; - $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); - $data = Media::addSectionMediaElement($src, 'oleObject'); - $rID = $data[0]; - $objectId = $data[1]; - $object->setRelationId($rID); - $object->setObjectId($objectId); - $object->setImageRelationId($rIDimg); - $this->_elementCollection[] = $object; - return $object; - } else { - throw new InvalidObjectException(); - } - } - - /** - * Add image element - * - * All exceptions should be handled by PhpOffice\PhpWord\Element\Image - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - $rID = Media::addSectionMediaElement($src, 'image', $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } - - /** - * Add memory image element - * - * @deprecated - * - * @param string $src - * @param mixed $style - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); + $this->elements[] = new PageBreak(); } /** @@ -281,82 +96,39 @@ class Section * * @param mixed $styleFont * @param mixed $styleTOC - * @return \PhpOffice\PhpWord\TOC + * @return TOC */ public function addTOC($styleFont = null, $styleTOC = null) { $toc = new TOC($styleFont, $styleTOC); - $this->_elementCollection[] = $toc; + $this->elements[] = $toc; return $toc; } /** - * Add a Title Element + * Add header * - * @param string $text - * @param int $depth - * @return \PhpOffice\PhpWord\Element\Title + * @return Header */ - public function addTitle($text, $depth = 1) + public function addHeader() { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $styles = Style::getStyles(); - if (array_key_exists('Heading_' . $depth, $styles)) { - $style = 'Heading' . $depth; - } else { - $style = null; - } - - $title = new Title($text, $depth, $style); - - $data = TOC::addTitle($text, $depth); - $anchor = $data[0]; - $bookmarkId = $data[1]; - - $title->setAnchor($anchor); - $title->setBookmarkId($bookmarkId); - - $this->_elementCollection[] = $title; - return $title; - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Get all Elements - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Create a new Header - * - * @return \PhpOffice\PhpWord\Container\Header - */ - public function createHeader() - { - $header = new Header($this->_sectionCount); - $this->_headers[] = $header; + $header = new Header($this->sectionId); + $this->headers[] = $header; return $header; } + /** + * Add footer + * + * @return Footer + */ + public function addFooter() + { + $footer = new Footer($this->sectionId); + $this->footer = $footer; + return $footer; + } + /** * Get Headers * @@ -364,7 +136,17 @@ class Section */ public function getHeaders() { - return $this->_headers; + return $this->headers; + } + + /** + * Get footer element + * + * @return Footer + */ + public function getFooter() + { + return $this->footer; } /** @@ -373,73 +155,33 @@ class Section * If any of the Header instances have a type of Header::FIRST then this method returns true. * False otherwise. * - * @return Boolean + * @return boolean */ public function hasDifferentFirstPage() { - $value = array_filter($this->_headers, function (Header &$header) { + $value = array_filter($this->headers, function (Header &$header) { return $header->getType() == Header::FIRST; }); return count($value) > 0; } /** - * Create a new Footer + * Create header * - * @return \PhpOffice\PhpWord\Container\Footer + * @deprecated 0.9.2 + */ + public function createHeader() + { + return $this->addHeader(); + } + + /** + * Create footer + * + * @deprecated 0.9.2 */ public function createFooter() { - $footer = new Footer($this->_sectionCount); - $this->_footer = $footer; - return $footer; - } - - /** - * Get footer element - * - * @return \PhpOffice\PhpWord\Container\Footer - */ - public function getFooter() - { - return $this->_footer; - } - - /** - * Create a new Footnote Element - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Footnote - */ - public function createFootnote($styleParagraph = null) - { - $footnote = new \PhpOffice\PhpWord\Element\Footnote($styleParagraph); - $refID = Footnote::addFootnoteElement($footnote); - $footnote->setReferenceId($refID); - $this->_elementCollection[] = $footnote; - return $footnote; - } - - /** - * Add a CheckBox Element - * - * @param string $name - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\CheckBox - */ - public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($name)) { - $name = utf8_encode($name); - } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $element = new CheckBox($name, $text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $element; - - return $element; + return $this->addFooter(); } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 5f247707..0781e2da 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -158,7 +158,7 @@ class Word2007 extends Writer implements IWriter $footers[++$_cFtrs] = $_footer; if (!is_null($_footer)) { $_footer->setRelationId(++$rID); - $_footerCount = $_footer->getFooterCount(); + $_footerCount = $_footer->getSectionId(); $_footerFile = 'footer' . $_footerCount . '.xml'; $sectionElements[] = array('target' => $_footerFile, 'type' => 'footer', 'rID' => $rID); $objZip->addFromString('word/' . $_footerFile, $this->getWriterPart('footer')->writeFooter($_footer)); diff --git a/tests/PhpWord/Tests/Container/FooterTest.php b/tests/PhpWord/Tests/Container/FooterTest.php index d9988ac5..74a09a51 100644 --- a/tests/PhpWord/Tests/Container/FooterTest.php +++ b/tests/PhpWord/Tests/Container/FooterTest.php @@ -27,7 +27,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $oFooter = new Footer($iVal); $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Footer', $oFooter); - $this->assertEquals($oFooter->getFooterCount(), $iVal); + $this->assertEquals($oFooter->getSectionId(), $iVal); } /** diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php index df1435de..9d479ade 100644 --- a/tests/PhpWord/Tests/Container/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -27,7 +27,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $oHeader = new Header($iVal); $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Header', $oHeader); - $this->assertEquals($oHeader->getHeaderCount(), $iVal); + $this->assertEquals($oHeader->getSectionId(), $iVal); $this->assertEquals($oHeader->getType(), Header::AUTO); } diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php index a61498ea..0517399c 100644 --- a/tests/PhpWord/Tests/Container/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -25,7 +25,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase public function testGetSettings() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getSettings(), '_settings', new Section(0)); + $this->assertAttributeEquals($oSection->getSettings(), 'settings', new Section(0)); } /** @@ -34,7 +34,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase public function testGetElements() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getElements(), '_elementCollection', new Section(0)); + $this->assertAttributeEquals($oSection->getElements(), 'elements', new Section(0)); } /** @@ -43,7 +43,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase public function testGetFooter() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getFooter(), '_footer', new Section(0)); + $this->assertAttributeEquals($oSection->getFooter(), 'footer', new Section(0)); } /** @@ -52,7 +52,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase public function testGetHeaders() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getHeaders(), '_headers', new Section(0)); + $this->assertAttributeEquals($oSection->getHeaders(), 'headers', new Section(0)); } /** From faba46cc059e0ba4e8df297051f0d9e746fecb89 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 31 Mar 2014 23:52:42 +0700 Subject: [PATCH 037/146] Extends `Container` abstract class into `Footnote`, `TextRun`, and `Cell` element class. --- src/PhpWord/Container/Container.php | 153 ++++++--- src/PhpWord/Element/Footnote.php | 102 +----- src/PhpWord/Element/Table/Cell.php | 313 ++---------------- src/PhpWord/Element/TextRun.php | 140 +------- .../PhpWord/Tests/Element/Table/CellTest.php | 4 +- 5 files changed, 166 insertions(+), 546 deletions(-) diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index 7ca3ebb1..379f7b14 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -57,6 +57,20 @@ abstract class Container */ protected $elements = array(); + /** + * Parent container type: section|header|footer + * + * @var string + */ + protected $parentContainer = null; + + /** + * Parent container Id + * + * @var int + */ + protected $parentContainerId; + /** * Relation Id * @@ -68,19 +82,22 @@ abstract class Container * Add text element * * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle * @return Text */ - public function addText($text, $styleFont = null, $styleParagraph = null) + public function addText($text, $fontStyle = null, $paragraphStyle = null) { + if (in_array($this->containerType, array('footnote', 'textrun'))) { + $paragraphStyle = null; + } if (!String::isUTF8($text)) { $text = utf8_encode($text); } - $text = new Text($text, $styleFont, $styleParagraph); - $this->elements[] = $text; + $element = new Text($text, $fontStyle, $paragraphStyle); + $this->elements[] = $element; - return $text; + return $element; } /** @@ -100,12 +117,16 @@ abstract class Container /** * Add textrun element * - * @param mixed $styleParagraph + * @param mixed $paragraphStyle * @return TextRun */ - public function addTextRun($styleParagraph = null) + public function addTextRun($paragraphStyle = null) { - $textRun = new TextRun($styleParagraph); + if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { + throw new \BadMethodCallException(); + } + + $textRun = new TextRun($paragraphStyle); $this->elements[] = $textRun; return $textRun; @@ -116,14 +137,17 @@ abstract class Container * * @param string $linkSrc * @param string $linkName - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle * @return Link * @todo Enable link element in header and footer */ - public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) + public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section', 'footnote', 'textrun', 'cell'))) { + throw new \BadMethodCallException(); + } + if ($this->containerType == 'cell' && $this->parentContainer != 'section') { throw new \BadMethodCallException(); } @@ -135,10 +159,15 @@ abstract class Container $linkName = utf8_encode($linkName); } } - $link = new Link($linkSrc, $linkName, $styleFont, $styleParagraph); - $rID = Media::addSectionLinkElement($linkSrc); + $link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle); + if ($this->containerType == 'footnote') { + $rID = Footnote::addFootnoteLinkElement($linkSrc); + } else { + $rID = Media::addSectionLinkElement($linkSrc); + } $link->setRelationId($rID); $this->elements[] = $link; + return $link; } @@ -148,7 +177,7 @@ abstract class Container * @param string $text * @param int $depth * @return Title - * @todo Enable title element in header and footer + * @todo Enable title element in header, footer, footnote, textrun */ public function addTitle($text, $depth = 1) { @@ -172,6 +201,7 @@ abstract class Container $title->setAnchor($anchor); $title->setBookmarkId($bookmarkId); $this->elements[] = $title; + return $title; } @@ -179,20 +209,23 @@ abstract class Container * Add preserve text element * * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle * @return PreserveText */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) + public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) { - if ($this->containerType == 'section') { + if (!in_array($this->containerType, array('header', 'footer', 'cell'))) { + throw new \BadMethodCallException(); + } + if ($this->containerType == 'cell' && $this->parentContainer == 'section') { throw new \BadMethodCallException(); } if (!String::isUTF8($text)) { $text = utf8_encode($text); } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); + $ptext = new PreserveText($text, $fontStyle, $paragraphStyle); $this->elements[] = $ptext; return $ptext; @@ -203,23 +236,27 @@ abstract class Container * * @param string $text * @param int $depth - * @param mixed $styleFont + * @param mixed $fontStyle * @param mixed $styleList - * @param mixed $styleParagraph + * @param mixed $paragraphStyle * @return ListItem * @todo Enable list item element in header and footer */ - public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) + public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section', 'cell'))) { + throw new \BadMethodCallException(); + } + if ($this->containerType == 'cell' && $this->parentContainer != 'section') { throw new \BadMethodCallException(); } if (!String::isUTF8($text)) { $text = utf8_encode($text); } - $listItem = new ListItem($text, $depth, $styleFont, $styleList, $styleParagraph); + $listItem = new ListItem($text, $depth, $fontStyle, $styleList, $paragraphStyle); $this->elements[] = $listItem; + return $listItem; } @@ -231,6 +268,10 @@ abstract class Container */ public function addTable($style = null) { + if (!in_array($this->containerType, array('section', 'header', 'footer'))) { + throw new \BadMethodCallException(); + } + $table = new Table($this->containerType, $this->sectionId, $style); $this->elements[] = $table; @@ -247,17 +288,29 @@ abstract class Container */ public function addImage($src, $style = null, $isWatermark = false) { + if ($this->containerType == 'footnote') { + throw new \BadMethodCallException(); + } + if (!is_null($this->parentContainer)) { + $imageContainerType = $this->parentContainer; + $imageContainerId = $this->parentContainerId; + } else { + $imageContainerType = $this->containerType; + $imageContainerId = $this->sectionId; + } + $image = new Image($src, $style, $isWatermark); if (!is_null($image->getSource())) { - switch ($this->containerType) { + switch ($imageContainerType) { + case 'textrun': case 'section': $rID = Media::addSectionMediaElement($src, 'image', $image); break; case 'header': - $rID = Media::addHeaderMediaElement($this->sectionId, $src, $image); + $rID = Media::addHeaderMediaElement($imageContainerId, $src, $image); break; case 'footer': - $rID = Media::addFooterMediaElement($this->sectionId, $src, $image); + $rID = Media::addFooterMediaElement($imageContainerId, $src, $image); break; } $image->setRelationId($rID); @@ -280,7 +333,10 @@ abstract class Container */ public function addObject($src, $style = null) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section', 'cell'))) { + throw new \BadMethodCallException(); + } + if ($this->containerType == 'cell' && $this->parentContainer != 'section') { throw new \BadMethodCallException(); } @@ -309,17 +365,17 @@ abstract class Container /** * Add footnote element * - * @param mixed $styleParagraph + * @param mixed $paragraphStyle * @return FootnoteElement * @todo Enable footnote element in header and footer */ - public function addFootnote($styleParagraph = null) + public function addFootnote($paragraphStyle = null) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section', 'textrun'))) { throw new \BadMethodCallException(); } - $footnote = new FootnoteElement($styleParagraph); + $footnote = new FootnoteElement($paragraphStyle); $refID = Footnote::addFootnoteElement($footnote); $footnote->setReferenceId($refID); $this->elements[] = $footnote; @@ -331,14 +387,17 @@ abstract class Container * * @param string $name * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle * @return CheckBox * @todo Enable checkbox element in header and footer */ - public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) + public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section', 'cell'))) { + throw new \BadMethodCallException(); + } + if ($this->containerType == 'cell' && $this->parentContainer != 'section') { throw new \BadMethodCallException(); } @@ -348,7 +407,7 @@ abstract class Container if (!String::isUTF8($text)) { $text = utf8_encode($text); } - $element = new CheckBox($name, $text, $styleFont, $styleParagraph); + $element = new CheckBox($name, $text, $fontStyle, $paragraphStyle); $this->elements[] = $element; return $element; @@ -380,7 +439,7 @@ abstract class Container */ public function getRelationId() { - if ($this->containerType == 'section') { + if (!in_array($this->containerType, array('header', 'footer'))) { throw new \BadMethodCallException(); } @@ -394,7 +453,7 @@ abstract class Container */ public function setRelationId($rId) { - if ($this->containerType == 'section') { + if (!in_array($this->containerType, array('header', 'footer'))) { throw new \BadMethodCallException(); } @@ -416,22 +475,22 @@ abstract class Container /** * Create textrun element * - * @param mixed $styleParagraph + * @param mixed $paragraphStyle * @deprecated 0.9.2 */ - public function createTextRun($styleParagraph = null) + public function createTextRun($paragraphStyle = null) { - return $this->addTextRun($styleParagraph); + return $this->addTextRun($paragraphStyle); } /** * Create footnote element * - * @param mixed $styleParagraph + * @param mixed $paragraphStyle * @deprecated 0.9.2 */ - public function createFootnote($styleParagraph = null) + public function createFootnote($paragraphStyle = null) { - return $this->addFootnote($styleParagraph); + return $this->addFootnote($paragraphStyle); } } diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index d1cb61cf..a683b3b0 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -9,125 +9,59 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Paragraph; /** * Footnote element */ -class Footnote +class Footnote extends Container { /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|Paragraph */ - private $_styleParagraph; + private $paragraphStyle; /** * Footnote Reference ID * * @var string */ - private $_refId; + private $referenceId; /** - * Text collection + * Create new instance * - * @var array + * @param string|array|Paragraph $paragraphStyle */ - private $_elementCollection; - - /** - * Create a new Footnote Element - * - * @param mixed $styleParagraph - */ - public function __construct($styleParagraph = null) + public function __construct($paragraphStyle = null) { - $this->_elementCollection = array(); + $this->containerType = 'footnote'; // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { + if (is_array($paragraphStyle)) { + $this->paragraphStyle = new Paragraph(); + foreach ($paragraphStyle as $key => $value) { if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - $this->_styleParagraph->setStyleValue($key, $value); + $this->paragraphStyle->setStyleValue($key, $value); } } else { - $this->_styleParagraph = $styleParagraph; + $this->paragraphStyle = $paragraphStyle; } } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text = null, $styleFont = null) - { - $givenText = $text; - $text = new Text($givenText, $styleFont); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add TextBreak - * - * @param int $count - * @param mixed $fontStyle - * @param mixed $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Element\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null) - { - - $link = new Link($linkSrc, $linkName, $styleFont); - $rID = \PhpOffice\PhpWord\Footnote::addFootnoteLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Get Footnote content - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - /** * Get paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|Paragraph */ public function getParagraphStyle() { - return $this->_styleParagraph; + return $this->paragraphStyle; } /** @@ -137,7 +71,7 @@ class Footnote */ public function getReferenceId() { - return $this->_refId; + return $this->referenceId; } /** @@ -147,6 +81,6 @@ class Footnote */ public function setReferenceId($refId) { - $this->_refId = $refId; + $this->referenceId = $refId; } } diff --git a/src/PhpWord/Element/Table/Cell.php b/src/PhpWord/Element/Table/Cell.php index 0e0d688e..0a14400c 100755 --- a/src/PhpWord/Element/Table/Cell.php +++ b/src/PhpWord/Element/Table/Cell.php @@ -9,76 +9,44 @@ namespace PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Exception\InvalidObjectException; -use PhpOffice\PhpWord\Exception\InvalidImageException; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Object; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\CheckBox; -use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Container\Container; +use PhpOffice\PhpWord\Style\Cell as CellStyle; /** * Table cell element */ -class Cell +class Cell extends Container { /** - * Cell Width + * Cell width * * @var int */ - private $_width = null; + private $width = null; /** - * Cell Style + * Cell style * - * @var \PhpOffice\PhpWord\Style\Cell + * @var CellStyle */ - private $_style; + private $cellStyle; /** - * Cell Element Collection + * Create new instance * - * @var array - */ - private $_elementCollection = array(); - - /** - * Table holder - * - * @var string - */ - private $_insideOf; - - /** - * Section/Header/Footer count - * - * @var int - */ - private $_pCount; - - - /** - * Create a new Table Cell - * - * @param string $insideOf - * @param int $pCount + * @param string $parentType section|header|footer + * @param int $parentId * @param int $width - * @param mixed $style + * @param array|CellStyle $style */ - public function __construct($insideOf, $pCount, $width = null, $style = null) + public function __construct($parentType, $parentId, $width = null, $style = null) { - $this->_insideOf = $insideOf; - $this->_pCount = $pCount; - $this->_width = $width; - $this->_style = new \PhpOffice\PhpWord\Style\Cell(); + $this->containerType = 'cell'; + + $this->parentContainer = $parentType; + $this->parentContainerId = $parentId; + $this->width = $width; + $this->cellStyle = new CellStyle(); if (!is_null($style)) { if (is_array($style)) { @@ -86,260 +54,31 @@ class Cell if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - $this->_style->setStyleValue($key, $value); + $this->cellStyle->setStyleValue($key, $value); } } else { - $this->_style = $style; + $this->cellStyle = $style; } } } /** - * Add a Text Element + * Get cell style * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Link - */ - public function addLink($linkSrc, $linkName = null, $style = null) - { - if ($this->_insideOf == 'section') { - if (!String::isUTF8($linkSrc)) { - $linkSrc = utf8_encode($linkSrc); - } - if (!is_null($linkName)) { - if (!String::isUTF8($linkName)) { - $linkName = utf8_encode($linkName); - } - } - - $link = new Link($linkSrc, $linkName, $style); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } else { - throw new Exception('Unsupported Link header / footer reference'); - return false; - } - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Add a ListItem Element - * - * @param string $text - * @param int $depth - * @param mixed $styleText - * @param mixed $styleList - * @return \PhpOffice\PhpWord\Element\ListItem - */ - public function addListItem($text, $depth = 0, $styleText = null, $styleList = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $listItem = new ListItem($text, $depth, $styleText, $styleList); - $this->_elementCollection[] = $listItem; - return $listItem; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - if ($this->_insideOf == 'section') { - $rID = Media::addSectionMediaElement($src, 'image', $image); - } elseif ($this->_insideOf == 'header') { - $rID = Media::addHeaderMediaElement($this->_pCount, $src, $image); - } elseif ($this->_insideOf == 'footer') { - $rID = Media::addFooterMediaElement($this->_pCount, $src, $image); - } - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $src - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a OLE-Object Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Object - */ - public function addObject($src, $style = null) - { - $object = new Object($src, $style); - - if (!is_null($object->getSource())) { - $inf = pathinfo($src); - $ext = $inf['extension']; - if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { - $ext = substr($ext, 0, -1); - } - - $iconSrc = __DIR__ . '/../../_staticDocParts/'; - if (!\file_exists($iconSrc . '_' . $ext . '.png')) { - $iconSrc = $iconSrc . '_default.png'; - } else { - $iconSrc .= '_' . $ext . '.png'; - } - - $rIDimg = Media::addSectionMediaElement($iconSrc, 'image', new Image($iconSrc)); - $data = Media::addSectionMediaElement($src, 'oleObject'); - $rID = $data[0]; - $objectId = $data[1]; - - $object->setRelationId($rID); - $object->setObjectId($objectId); - $object->setImageRelationId($rIDimg); - - $this->_elementCollection[] = $object; - return $object; - } else { - throw new InvalidObjectException; - } - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if ($this->_insideOf == 'footer' || $this->_insideOf == 'header') { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; - } else { - throw new Exception('addPreserveText only supported in footer/header.'); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Add a CheckBox Element - * - * @param string $name - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\CheckBox - */ - public function addCheckBox($name, $text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($name)) { - $name = utf8_encode($name); - } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new CheckBox($name, $text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Get all Elements - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Cell Style - * - * @return \PhpOffice\PhpWord\Style\Cell + * @return CellStyle */ public function getStyle() { - return $this->_style; + return $this->cellStyle; } /** - * Get Cell width + * Get cell width * * @return int */ public function getWidth() { - return $this->_width; + return $this->width; } } diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index a890bb04..63401d33 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -9,156 +9,44 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exception\InvalidImageException; -use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Shared\String; -use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Paragraph; /** * Textrun/paragraph element */ -class TextRun +class TextRun extends Container { /** * Paragraph style * - * @var Paragraph + * @var string|Paragraph */ - private $_styleParagraph; + private $paragraphStyle; /** - * Text collection + * Create new instance * - * @var array + * @param string|array|Paragraph $paragraphStyle */ - private $_elementCollection; - - - /** - * Create a new TextRun Element - * - * @param mixed $styleParagraph - */ - public function __construct($styleParagraph = null) + public function __construct($paragraphStyle = null) { - $this->_elementCollection = array(); + $this->containerType = 'textrun'; // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { + if (is_array($paragraphStyle)) { + $this->paragraphStyle = new Paragraph(); + foreach ($paragraphStyle as $key => $value) { if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - $this->_styleParagraph->setStyleValue($key, $value); + $this->paragraphStyle->setStyleValue($key, $value); } } else { - $this->_styleParagraph = $styleParagraph; + $this->paragraphStyle = $paragraphStyle; } } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Element\Text - */ - public function addText($text = null, $styleFont = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Element\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null) - { - $linkSrc = utf8_encode($linkSrc); - if (!is_null($linkName)) { - $linkName = utf8_encode($linkName); - } - - $link = new Link($linkSrc, $linkName, $styleFont); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Add a Image Element - * - * @param string $imageSrc - * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Image - */ - public function addImage($imageSrc, $style = null) - { - $image = new Image($imageSrc, $style); - if (!is_null($image->getSource())) { - $rID = Media::addSectionMediaElement($imageSrc, 'image', $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add TextBreak - * - * @param int $count - * @param mixed $fontStyle - * @param mixed $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new Footnote Element - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Element\Footnote - */ - public function createFootnote($styleParagraph = null) - { - $footnote = new \PhpOffice\PhpWord\Element\Footnote($styleParagraph); - $refID = \PhpOffice\PhpWord\Footnote::addFootnoteElement($footnote); - $footnote->setReferenceId($refID); - $this->_elementCollection[] = $footnote; - return $footnote; - } - - /** - * Get TextRun content - * - * @return string - */ - public function getElements() - { - return $this->_elementCollection; - } - /** * Get Paragraph style * @@ -166,6 +54,6 @@ class TextRun */ public function getParagraphStyle() { - return $this->_styleParagraph; + return $this->paragraphStyle; } } diff --git a/tests/PhpWord/Tests/Element/Table/CellTest.php b/tests/PhpWord/Tests/Element/Table/CellTest.php index 661120d4..b8daca61 100644 --- a/tests/PhpWord/Tests/Element/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/Table/CellTest.php @@ -92,7 +92,7 @@ class CellTest extends \PHPUnit_Framework_TestCase /** * Add link exception - * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedException \BadMethodCallException */ public function testAddLinkException() { @@ -272,7 +272,7 @@ class CellTest extends \PHPUnit_Framework_TestCase /** * Add preserve text exception * - * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedException \BadMethodCallException */ public function testAddPreserveTextException() { From 07be5eaea326a43fe0c68b6231c4a74e9639dd99 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 1 Apr 2014 15:01:30 +0700 Subject: [PATCH 038/146] Adding more functionalities to containers: - Table: Ability to add footnote in table cell - Footnote: Ability to add image in footnote - ListItem: Ability to add list item in header/footer - CheckBox: Ability to add checkbox in header/footer - Link: Ability to add link in header/footer --- CHANGELOG.md | 9 +- samples/Sample_04_Textrun.php | 2 +- samples/Sample_06_Footnote.php | 19 +- samples/Sample_09_Tables.php | 15 +- samples/Sample_12_HeaderFooter.php | 6 +- src/PhpWord/Container/Container.php | 113 ++++----- src/PhpWord/Element/Footnote.php | 1 - src/PhpWord/Element/Table/Cell.php | 11 +- src/PhpWord/Element/TextRun.php | 7 +- src/PhpWord/Footnote.php | 53 ++-- src/PhpWord/Media.php | 240 +++++++++++------- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Shared/String.php | 15 ++ src/PhpWord/Shared/XMLWriter.php | 2 + src/PhpWord/Writer/Word2007.php | 94 ++++--- src/PhpWord/Writer/Word2007/Base.php | 10 +- src/PhpWord/Writer/Word2007/Document.php | 22 +- src/PhpWord/Writer/Word2007/DocumentRels.php | 4 +- src/PhpWord/Writer/Word2007/Footer.php | 25 +- src/PhpWord/Writer/Word2007/Footnotes.php | 28 +- src/PhpWord/Writer/Word2007/Header.php | 26 +- .../PhpWord/Tests/Element/Table/CellTest.php | 10 - tests/PhpWord/Tests/FootnoteTest.php | 3 +- tests/PhpWord/Tests/MediaTest.php | 4 +- 24 files changed, 419 insertions(+), 302 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9c5d39a..24f6ac85 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 - Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 - Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 +- Table: Ability to add footnote in table cell - @ivanlanin GH-187 +- Footnote: Ability to add image in footnote - @ivanlanin GH-187 +- ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 +- CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 +- Link: Ability to add link in header/footer - @ivanlanin GH-187 ### Bugfixes @@ -24,8 +29,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Documentation: Simplify page level docblock - @ivanlanin GH-179 - Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 - Reader: Rename AbstractReader > Reader - @ivanlanin -- General: Refactor folders: Element, Container, and Exception - @ivanlanin -- Container: Create new Container abstract class - @ivanlanin +- General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187 +- Container: Create new Container abstract class - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 94bc3d5b..d289457d 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -28,7 +28,7 @@ $textrun->addText(' All elements are placed inside a paragraph with the optional $textrun->addText(' Sample Link: '); $textrun->addLink('http://www.google.com', null, 'NLink'); $textrun->addText(' Sample Image: '); -$textrun->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); +$textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); $textrun->addText(' Here is some more text. '); // Save file diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 081d5918..e35f5d6b 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -4,6 +4,7 @@ include_once 'Sample_Header.php'; // New Word Document echo date('H:i:s') , " Create new PhpWord object" , \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +\PhpOffice\PhpWord\Settings::setCompatibility(false); // New portrait section $section = $phpWord->createSection(); @@ -19,16 +20,16 @@ $textrun = $section->createTextRun('pStyle'); $textrun->addText('This is some lead text in a paragraph with a following footnote. ','pStyle'); $footnote = $textrun->createFootnote(); -$footnote->addText('Just like a textrun a footnote can contain native text and link elements.'); -$footnote->addText(' No break is placed after adding an element.', 'BoldText'); -$footnote->addText(' All elements are placed inside a paragraph.', 'ColoredText'); -$footnote->addText(' The best search engine: '); -$footnote->addLink('http://www.google.com', null, 'NLink'); -$footnote->addText('. Also not bad:'); +$footnote->addText('Just like a textrun, a footnote can contain native texts. '); +$footnote->addText('No break is placed after adding an element. ', 'BoldText'); +$footnote->addText('All elements are placed inside a paragraph. ', 'ColoredText'); $footnote->addTextBreak(); -$footnote->addLink('http://www.bing.com', null, 'NLink'); - -$textrun->addText('The trailing text in the paragraph.'); +$footnote->addText('But you can insert a manual text break like above, '); +$footnote->addText('links like '); +$footnote->addLink('http://www.google.com', null, 'NLink'); +$footnote->addText(', or image like '); +$footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.'); $footnote = $section->createFootnote(); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index ea10eec9..0c9fbeb5 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -63,10 +63,21 @@ $cellVCentered = array('valign' => 'center'); $phpWord->addTableStyle('Colspan Rowspan', $styleTable); $table = $section->addTable('Colspan Rowspan'); + $table->addRow(); -$table->addCell(2000, $cellRowSpan)->addText('A', null, $cellHCentered); -$table->addCell(4000, $cellColSpan)->addText('B', null, $cellHCentered); + +$cell1 = $table->addCell(2000, $cellRowSpan); +$textrun1 = $cell1->addTextRun($cellHCentered); +$textrun1->addText('A'); +$textrun1->addFootnote()->addText('Row span'); + +$cell2 = $table->addCell(4000, $cellColSpan); +$textrun2 = $cell2->addTextRun($cellHCentered); +$textrun2->addText('B'); +$textrun2->addFootnote()->addText('Colspan span'); + $table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered); + $table->addRow(); $table->addCell(null, $cellRowContinue); $table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 3c5775ef..19139ab2 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -13,7 +13,10 @@ $header = $section->createHeader(); $header->firstPage(); $table = $header->addTable(); $table->addRow(); -$table->addCell(4500)->addText('This is the header.'); +$cell = $table->addCell(4500); +$textrun = $cell->addTextRun(); +$textrun->addText('This is the header with '); +$textrun->addLink('http://google.com', 'link to Google'); $table->addCell(4500)->addImage( 'resources/PhpWord.png', array('width' => 80, 'height' => 80, 'align' => 'right') @@ -26,6 +29,7 @@ $subsequent->addText("Subsequent pages in Section 1 will Have this!"); // Add footer $footer = $section->createFooter(); $footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', array('align' => 'center')); +$footer->addLink('http://google.com', 'Direct Google'); // Write some text $section->addTextBreak(); diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index 379f7b14..a29e393c 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Exception\InvalidObjectException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Footnote; +use PhpOffice\PhpWord\Footnote as FootnoteCollection; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; @@ -58,18 +58,22 @@ abstract class Container protected $elements = array(); /** - * Parent container type: section|header|footer + * Document part type: section|header|footer + * + * Used by textrun and cell to determine where the element is located + * because it will affect the availability of other element, e.g. footnote + * will not be available when $docPartType is header or footer. * * @var string */ - protected $parentContainer = null; + protected $docPartType = null; /** - * Parent container Id + * Document part Id * * @var int */ - protected $parentContainerId; + protected $docPartId; /** * Relation Id @@ -91,9 +95,7 @@ abstract class Container if (in_array($this->containerType, array('footnote', 'textrun'))) { $paragraphStyle = null; } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } + $text = String::toUTF8($text); $element = new Text($text, $fontStyle, $paragraphStyle); $this->elements[] = $element; @@ -125,8 +127,15 @@ abstract class Container if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { throw new \BadMethodCallException(); } + if ($this->containerType == 'cell') { + $docPartType = $this->docPartType; + $docPartId = $this->docPartId; + } else { + $docPartType = $this->containerType; + $docPartId = $this->sectionId; + } - $textRun = new TextRun($paragraphStyle); + $textRun = new TextRun($paragraphStyle, $docPartType, $docPartId); $this->elements[] = $textRun; return $textRun; @@ -140,30 +149,27 @@ abstract class Container * @param mixed $fontStyle * @param mixed $paragraphStyle * @return Link - * @todo Enable link element in header and footer */ public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'footnote', 'textrun', 'cell'))) { - throw new \BadMethodCallException(); + if (!is_null($this->docPartType)) { + $linkContainer = $this->docPartType; + $linkContainerId = $this->docPartId; + } else { + $linkContainer = $this->containerType; + $linkContainerId = $this->sectionId; } - if ($this->containerType == 'cell' && $this->parentContainer != 'section') { - throw new \BadMethodCallException(); + if ($linkContainer == 'header' || $linkContainer == 'footer') { + $linkContainer .= $linkContainerId; } - if (!String::isUTF8($linkSrc)) { - $linkSrc = utf8_encode($linkSrc); - } - if (!is_null($linkName)) { - if (!String::isUTF8($linkName)) { - $linkName = utf8_encode($linkName); - } - } + $linkSrc = String::toUTF8($linkSrc); + $linkName = String::toUTF8($linkName); $link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle); - if ($this->containerType == 'footnote') { - $rID = Footnote::addFootnoteLinkElement($linkSrc); - } else { + if ($linkContainer == 'section') { $rID = Media::addSectionLinkElement($linkSrc); + } else { + $rID = Media::addMediaElement($linkContainer, 'hyperlink', $linkSrc); } $link->setRelationId($rID); $this->elements[] = $link; @@ -181,13 +187,11 @@ abstract class Container */ public function addTitle($text, $depth = 1) { - if ($this->containerType != 'section') { + if (!in_array($this->containerType, array('section'))) { throw new \BadMethodCallException(); } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } + $text = String::toUTF8($text); $styles = Style::getStyles(); if (array_key_exists('Heading_' . $depth, $styles)) { $style = 'Heading' . $depth; @@ -218,13 +222,11 @@ abstract class Container if (!in_array($this->containerType, array('header', 'footer', 'cell'))) { throw new \BadMethodCallException(); } - if ($this->containerType == 'cell' && $this->parentContainer == 'section') { + if ($this->containerType == 'cell' && $this->docPartType == 'section') { throw new \BadMethodCallException(); } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } + $text = String::toUTF8($text); $ptext = new PreserveText($text, $fontStyle, $paragraphStyle); $this->elements[] = $ptext; @@ -244,16 +246,11 @@ abstract class Container */ public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'cell'))) { - throw new \BadMethodCallException(); - } - if ($this->containerType == 'cell' && $this->parentContainer != 'section') { + if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { throw new \BadMethodCallException(); } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } + $text = String::toUTF8($text); $listItem = new ListItem($text, $depth, $fontStyle, $styleList, $paragraphStyle); $this->elements[] = $listItem; @@ -288,12 +285,9 @@ abstract class Container */ public function addImage($src, $style = null, $isWatermark = false) { - if ($this->containerType == 'footnote') { - throw new \BadMethodCallException(); - } - if (!is_null($this->parentContainer)) { - $imageContainerType = $this->parentContainer; - $imageContainerId = $this->parentContainerId; + if ($this->containerType == 'cell') { + $imageContainerType = $this->docPartType; + $imageContainerId = $this->docPartId; } else { $imageContainerType = $this->containerType; $imageContainerId = $this->sectionId; @@ -301,6 +295,7 @@ abstract class Container $image = new Image($src, $style, $isWatermark); if (!is_null($image->getSource())) { + $rID = null; switch ($imageContainerType) { case 'textrun': case 'section': @@ -312,6 +307,9 @@ abstract class Container case 'footer': $rID = Media::addFooterMediaElement($imageContainerId, $src, $image); break; + case 'footnote': + $rID = Media::addMediaElement('footnotes', 'image', $src, $image); + break; } $image->setRelationId($rID); $this->elements[] = $image; @@ -336,7 +334,7 @@ abstract class Container if (!in_array($this->containerType, array('section', 'cell'))) { throw new \BadMethodCallException(); } - if ($this->containerType == 'cell' && $this->parentContainer != 'section') { + if ($this->containerType == 'cell' && $this->docPartType != 'section') { throw new \BadMethodCallException(); } @@ -367,18 +365,21 @@ abstract class Container * * @param mixed $paragraphStyle * @return FootnoteElement - * @todo Enable footnote element in header and footer */ public function addFootnote($paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'textrun'))) { + if (!in_array($this->containerType, array('section', 'textrun', 'cell'))) { + throw new \BadMethodCallException(); + } + if (!is_null($this->docPartType) && $this->docPartType != 'section') { throw new \BadMethodCallException(); } $footnote = new FootnoteElement($paragraphStyle); - $refID = Footnote::addFootnoteElement($footnote); + $refID = FootnoteCollection::addFootnoteElement($footnote); $footnote->setReferenceId($refID); $this->elements[] = $footnote; + return $footnote; } @@ -394,19 +395,15 @@ abstract class Container */ public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'cell'))) { + if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { throw new \BadMethodCallException(); } - if ($this->containerType == 'cell' && $this->parentContainer != 'section') { + if ($this->containerType == 'cell' && $this->docPartType != 'section') { throw new \BadMethodCallException(); } - if (!String::isUTF8($name)) { - $name = utf8_encode($name); - } - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } + $name = String::toUTF8($name); + $text = String::toUTF8($text); $element = new CheckBox($name, $text, $fontStyle, $paragraphStyle); $this->elements[] = $element; diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index a683b3b0..aa6af010 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -39,7 +39,6 @@ class Footnote extends Container public function __construct($paragraphStyle = null) { $this->containerType = 'footnote'; - // Set paragraph style if (is_array($paragraphStyle)) { $this->paragraphStyle = new Paragraph(); diff --git a/src/PhpWord/Element/Table/Cell.php b/src/PhpWord/Element/Table/Cell.php index 0a14400c..3f795a28 100755 --- a/src/PhpWord/Element/Table/Cell.php +++ b/src/PhpWord/Element/Table/Cell.php @@ -34,17 +34,16 @@ class Cell extends Container /** * Create new instance * - * @param string $parentType section|header|footer - * @param int $parentId + * @param string $docPartType section|header|footer + * @param int $docPartId * @param int $width * @param array|CellStyle $style */ - public function __construct($parentType, $parentId, $width = null, $style = null) + public function __construct($docPartType, $docPartId, $width = null, $style = null) { $this->containerType = 'cell'; - - $this->parentContainer = $parentType; - $this->parentContainerId = $parentId; + $this->docPartType = $docPartType; + $this->docPartId = $docPartId; $this->width = $width; $this->cellStyle = new CellStyle(); diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 63401d33..35701d45 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -28,11 +28,14 @@ class TextRun extends Container * Create new instance * * @param string|array|Paragraph $paragraphStyle + * @param string $docPartType section|header|footer + * @param int $docPartId */ - public function __construct($paragraphStyle = null) + public function __construct($paragraphStyle = null, $docPartType = 'section', $docPartId = 1) { $this->containerType = 'textrun'; - + $this->docPartType = $docPartType; + $this->docPartId = $docPartId; // Set paragraph style if (is_array($paragraphStyle)) { $this->paragraphStyle = new Paragraph(); diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index af104bc8..2ec3d0b3 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -9,35 +9,32 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\Element\Footnote as FootnoteElement; + /** * Footnote */ class Footnote { /** - * Footnote Elements + * Footnote elements * * @var array */ - private static $_footnoteCollection = array(); + private static $elements = array(); /** - * Footnote Link Elements - * - * @var array - */ - private static $_footnoteLink = array(); - - /** - * Add new Footnote Element + * Add new footnote * + * @param FootnoteElement $footnote * @return int Reference ID */ - public static function addFootnoteElement(\PhpOffice\PhpWord\Element\Footnote $footnote) + public static function addFootnoteElement(FootnoteElement $footnote) { - $refID = self::countFootnoteElements() + 2; + $refID = self::countFootnoteElements() + 1; - self::$_footnoteCollection[] = $footnote; + self::$elements[] = $footnote; return $refID; } @@ -49,7 +46,7 @@ class Footnote */ public static function getFootnoteElements() { - return self::$_footnoteCollection; + return self::$elements; } /** @@ -59,47 +56,29 @@ class Footnote */ public static function countFootnoteElements() { - return count(self::$_footnoteCollection); + return count(self::$elements); } /** * Add new Footnote Link Element * * @param string $linkSrc - * * @return int Reference ID + * @deprecated 0.9.2 */ public static function addFootnoteLinkElement($linkSrc) { - $rID = self::countFootnoteLinkElements() + 1; - - $link = array(); - $link['target'] = $linkSrc; - $link['rID'] = $rID; - $link['type'] = 'hyperlink'; - - self::$_footnoteLink[] = $link; - - return $rID; + return Media::addMediaElement('footnotes', 'hyperlink', $linkSrc); } /** * Get Footnote Link Elements * * @return array + * @deprecated 0.9.2 */ public static function getFootnoteLinkElements() { - return self::$_footnoteLink; - } - - /** - * Get Footnote Link Elements Count - * - * @return int - */ - public static function countFootnoteLinkElements() - { - return count(self::$_footnoteLink); + return Media::getMediaElements('footnotes', 'hyperlink'); } } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 35800f92..c8b33301 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -21,7 +21,7 @@ class Media * * @var array */ - private static $_sectionMedia = array( + private static $sectionMedia = array( 'images' => array(), 'embeddings' => array(), 'links' => array() @@ -32,35 +32,42 @@ class Media * * @var array */ - private static $_headerMedia = array(); + private static $headerMedia = array(); /** * Footer Media Elements * * @var array */ - private static $_footerMedia = array(); + private static $footerMedia = array(); + + /** + * Media elements + * + * @var array + */ + private static $media = array(); /** * ObjectID Counter * * @var int */ - private static $_objectId = 1325353440; + private static $objectId = 1325353440; /** * Add new Section Media Element * * @param string $src * @param string $type - * @param \PhpOffice\PhpWord\Element\Image $image + * @param Image $image * @return mixed */ public static function addSectionMediaElement($src, $type, Image $image = null) { $mediaId = md5($src); $key = ($type === 'image') ? 'images' : 'embeddings'; - if (!array_key_exists($mediaId, self::$_sectionMedia[$key])) { + if (!array_key_exists($mediaId, self::$sectionMedia[$key])) { $cImg = self::countSectionMediaElements('images'); $cObj = self::countSectionMediaElements('embeddings'); $rID = self::countSectionMediaElements() + 7; @@ -90,17 +97,17 @@ class Media $media['target'] = "$folder/section_$file"; $media['type'] = $type; $media['rID'] = $rID; - self::$_sectionMedia[$key][$mediaId] = $media; + self::$sectionMedia[$key][$mediaId] = $media; if ($type === 'oleObject') { - return array($rID, ++self::$_objectId); + return array($rID, ++self::$objectId); } return $rID; } else { if ($type === 'oleObject') { - $rID = self::$_sectionMedia[$key][$mediaId]['rID']; - return array($rID, ++self::$_objectId); + $rID = self::$sectionMedia[$key][$mediaId]['rID']; + return array($rID, ++self::$objectId); } - return self::$_sectionMedia[$key][$mediaId]['rID']; + return self::$sectionMedia[$key][$mediaId]['rID']; } } @@ -119,7 +126,7 @@ class Media $link['rID'] = $rID; $link['type'] = 'hyperlink'; - self::$_sectionMedia['links'][] = $link; + self::$sectionMedia['links'][] = $link; return $rID; } @@ -133,12 +140,12 @@ class Media public static function getSectionMediaElements($key = null) { if (!is_null($key)) { - return self::$_sectionMedia[$key]; + return self::$sectionMedia[$key]; } - $arrImages = self::$_sectionMedia['images']; - $arrObjects = self::$_sectionMedia['embeddings']; - $arrLinks = self::$_sectionMedia['links']; + $arrImages = self::$sectionMedia['images']; + $arrObjects = self::$sectionMedia['embeddings']; + $arrLinks = self::$sectionMedia['links']; return array_merge($arrImages, $arrObjects, $arrLinks); } @@ -151,12 +158,12 @@ class Media public static function countSectionMediaElements($key = null) { if (!is_null($key)) { - return count(self::$_sectionMedia[$key]); + return count(self::$sectionMedia[$key]); } - $cImages = count(self::$_sectionMedia['images']); - $cObjects = count(self::$_sectionMedia['embeddings']); - $cLinks = count(self::$_sectionMedia['links']); + $cImages = count(self::$sectionMedia['images']); + $cObjects = count(self::$sectionMedia['embeddings']); + $cLinks = count(self::$sectionMedia['links']); return ($cImages + $cObjects + $cLinks); } @@ -165,41 +172,12 @@ class Media * * @param int $headerCount * @param string $src - * @param \PhpOffice\PhpWord\Element\Image $image + * @param Image $image * @return int */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) { - $mediaId = md5($src); - $key = 'header' . $headerCount; - if (!array_key_exists($key, self::$_headerMedia)) { - self::$_headerMedia[$key] = array(); - } - if (!array_key_exists($mediaId, self::$_headerMedia[$key])) { - $cImg = self::countHeaderMediaElements($key); - $rID = $cImg + 1; - $cImg++; - $media = array(); - $isMemImage = false; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $file = 'image' . $cImg . '.' . strtolower($extension); - $media['source'] = $src; - $media['target'] = 'media/' . $key . '_' . $file; - $media['type'] = 'image'; - $media['rID'] = $rID; - self::$_headerMedia[$key][$mediaId] = $media; - return $rID; - } else { - return self::$_headerMedia[$key][$mediaId]['rID']; - } + return self::addMediaElement("header{$headerCount}", 'image', $src, $image); } /** @@ -210,17 +188,26 @@ class Media */ public static function countHeaderMediaElements($key) { - return count(self::$_headerMedia[$key]); + return self::countMediaElements($key); } /** * Get Header Media Elements * - * @return int + * @return array */ - public static function getHeaderMediaElements() + public static function getHeaderMediaElements($prefix = 'header') { - return self::$_headerMedia; + $mediaCollection = array(); + if (!empty(self::$media)) { + foreach (self::$media as $key => $val) { + if (substr($key, 0, 6) == $prefix) { + $mediaCollection[$key] = $val; + } + } + } + + return $mediaCollection; } /** @@ -228,41 +215,12 @@ class Media * * @param int $footerCount * @param string $src - * @param \PhpOffice\PhpWord\Element\Image $image + * @param Image $image * @return int */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) { - $mediaId = md5($src); - $key = 'footer' . $footerCount; - if (!array_key_exists($key, self::$_footerMedia)) { - self::$_footerMedia[$key] = array(); - } - if (!array_key_exists($mediaId, self::$_footerMedia[$key])) { - $cImg = self::countFooterMediaElements($key); - $rID = $cImg + 1; - $cImg++; - $media = array(); - $isMemImage = false; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $file = 'image' . $cImg . '.' . strtolower($extension); - $media['source'] = $src; - $media['target'] = 'media/' . $key . '_' . $file; - $media['type'] = 'image'; - $media['rID'] = $rID; - self::$_footerMedia[$key][$mediaId] = $media; - return $rID; - } else { - return self::$_footerMedia[$key][$mediaId]['rID']; - } + return self::addMediaElement("footer{$footerCount}", 'image', $src, $image); } /** @@ -273,16 +231,120 @@ class Media */ public static function countFooterMediaElements($key) { - return count(self::$_footerMedia[$key]); + return self::countMediaElements($key); } /** * Get Footer Media Elements * - * @return int + * @return array */ public static function getFooterMediaElements() { - return self::$_footerMedia; + return self::getHeaderMediaElements('footer'); + } + + /** + * Add new media element + * + * @param string $container section|header|footer|footnotes + * @param string $mediaType image|embedding|hyperlink + * @param string $source + * @param Image $image + * @return int + */ + public static function addMediaElement($container, $mediaType, $source, Image $image = null) + { + // Assign media Id and initiate media container if none exists + $mediaId = md5($source); + if (!array_key_exists($container, self::$media)) { + self::$media[$container]= array(); + } + + // Add media if not exists or point to existing media + if (!array_key_exists($mediaId, self::$media[$container])) { + $mediaCount = self::countMediaElements($container); + $mediaTypeCount = self::countMediaElements($container, $mediaType); + $mediaData = array(); + $relId = $mediaCount + 1; + $mediaTypeCount++; + if ($mediaType == 'image') { + $isMemImage = false; + if (!is_null($image)) { + $isMemImage = $image->getIsMemImage(); + $extension = $image->getImageExtension(); + } + if ($isMemImage) { + $mediaData['isMemImage'] = true; + $mediaData['createfunction'] = $image->getImageCreateFunction(); + $mediaData['imagefunction'] = $image->getImageFunction(); + } + $file = 'image' . $mediaTypeCount . '.' . strtolower($extension); + if ($container != 'footnotes') { + $file = $container . '_' . $file; + } + $target = 'media/' . $file; + } elseif ($mediaType == 'hyperlink') { + $target = $source; + } + $mediaData['source'] = $source; + $mediaData['target'] = $target; + $mediaData['type'] = $mediaType; + $mediaData['rID'] = $relId; + self::$media[$container][$mediaId] = $mediaData; + + return $relId; + } else { + return self::$media[$container][$mediaId]['rID']; + } + } + + /** + * Get media elements count + * + * @param string $container + * @param string $mediaType + * @return int + */ + public static function countMediaElements($container, $mediaType = null) + { + $mediaCount = 0; + foreach (self::$media[$container] as $mediaKey => $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaCount++; + } + } else { + $mediaCount++; + } + } + + return $mediaCount; + } + + /** + * Get media elements + * + * @param string $container + * @return int + */ + public static function getMediaElements($container, $mediaType = null) + { + if (!array_key_exists($container, self::$media)) { + return false; + } + + $mediaElements = array(); + foreach (self::$media[$container] as $mediaKey => $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaElements[$mediaKey] = $mediaData; + } + } else { + $mediaElements[$mediaKey] = $mediaData; + } + } + + return $mediaElements; } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 12cf4e6b..36ff79e3 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -194,7 +194,7 @@ class Word2007 extends Reader implements IReader ); // w:r more than 1? It's a textrun } else { - $textRun = $section->createTextRun(); + $textRun = $section->addTextRun(); foreach ($elm->r as $r) { $textRun->addText( $r->t, diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 262d3e42..9d298a66 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -91,4 +91,19 @@ class String { return $value === '' || preg_match('/^./su', $value) === 1; } + + /** + * Return UTF8 encoded value + * + * @param string $value + * @return string + */ + public static function toUTF8($value = '') + { + if (!is_null($value) && !self::isUTF8($value)) { + $value = utf8_encode($value); + } + + return $value; + } } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index e27013d5..16bb8334 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -24,6 +24,8 @@ if (!defined('DATE_W3C')) { * @method bool startElement(string $name) * @method bool writeAttribute(string $name, string $value) * @method bool endElement() + * @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null) + * @method bool text(string $content) */ class XMLWriter { diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 0781e2da..dd144da1 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -102,6 +102,7 @@ class Word2007 extends Writer implements IWriter } } + // Add section elements $sectionElements = array(); $_secElements = Media::getSectionMediaElements(); foreach ($_secElements as $element) { // loop through section media elements @@ -111,67 +112,94 @@ class Word2007 extends Writer implements IWriter $sectionElements[] = $element; } - $_hdrElements = Media::getHeaderMediaElements(); - foreach ($_hdrElements as $_headerFile => $_hdrMedia) { // loop through headers - if (count($_hdrMedia) > 0) { - $objZip->addFromString('word/_rels/' . $_headerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_hdrMedia)); - foreach ($_hdrMedia as $element) { // loop through header media elements - $this->addFileToPackage($objZip, $element); + // Add header relations & elements + $hdrElements = Media::getHeaderMediaElements(); + foreach ($hdrElements as $hdrFile => $hdrMedia) { + if (count($hdrMedia) > 0) { + $objZip->addFromString( + 'word/_rels/' . $hdrFile . '.xml.rels', + $this->getWriterPart('documentrels')->writeHeaderFooterRels($hdrMedia) + ); + foreach ($hdrMedia as $element) { + if ($element['type'] == 'image') { + $this->addFileToPackage($objZip, $element); + } } } } - $_ftrElements = Media::getFooterMediaElements(); - foreach ($_ftrElements as $_footerFile => $_ftrMedia) { // loop through footers - if (count($_ftrMedia) > 0) { - $objZip->addFromString('word/_rels/' . $_footerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_ftrMedia)); - foreach ($_ftrMedia as $element) { // loop through footers media elements - $this->addFileToPackage($objZip, $element); + // Add footer relations & elements + $ftrElements = Media::getFooterMediaElements(); + foreach ($ftrElements as $ftrFile => $ftrMedia) { + if (count($ftrMedia) > 0) { + $objZip->addFromString( + 'word/_rels/' . $ftrFile . '.xml.rels', + $this->getWriterPart('documentrels')->writeHeaderFooterRels($ftrMedia) + ); + foreach ($ftrMedia as $element) { + if ($element['type'] == 'image') { + $this->addFileToPackage($objZip, $element); + } } } } - $footnoteLinks = array(); - $_footnoteElements = Footnote::getFootnoteLinkElements(); - // loop through footnote link elements - foreach ($_footnoteElements as $element) { - $footnoteLinks[] = $element; - } - + // Process header/footer xml files $_cHdrs = 0; $_cFtrs = 0; $rID = Media::countSectionMediaElements() + 6; $_sections = $this->phpWord->getSections(); - $footers = array(); foreach ($_sections as $section) { $_headers = $section->getHeaders(); foreach ($_headers as $index => &$_header) { $_cHdrs++; $_header->setRelationId(++$rID); - $_headerFile = 'header' . $_cHdrs . '.xml'; - $sectionElements[] = array('target' => $_headerFile, 'type' => 'header', 'rID' => $rID); - $objZip->addFromString('word/' . $_headerFile, $this->getWriterPart('header')->writeHeader($_header)); + $hdrFile = 'header' . $_cHdrs . '.xml'; + $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); + $objZip->addFromString( + 'word/' . $hdrFile, + $this->getWriterPart('header')->writeHeader($_header) + ); } - $_footer = $section->getFooter(); $footers[++$_cFtrs] = $_footer; if (!is_null($_footer)) { $_footer->setRelationId(++$rID); $_footerCount = $_footer->getSectionId(); - $_footerFile = 'footer' . $_footerCount . '.xml'; - $sectionElements[] = array('target' => $_footerFile, 'type' => 'footer', 'rID' => $rID); - $objZip->addFromString('word/' . $_footerFile, $this->getWriterPart('footer')->writeFooter($_footer)); + $ftrFile = 'footer' . $_footerCount . '.xml'; + $sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID); + $objZip->addFromString( + 'word/' . $ftrFile, + $this->getWriterPart('footer')->writeFooter($_footer) + ); } } + // Process footnotes if (Footnote::countFootnoteElements() > 0) { - $_allFootnotesCollection = Footnote::getFootnoteElements(); - $_footnoteFile = 'footnotes.xml'; - $sectionElements[] = array('target'=>$_footnoteFile, 'type'=>'footnotes', 'rID'=>++$rID); - $objZip->addFromString('word/'.$_footnoteFile, $this->getWriterPart('footnotes')->writeFootnotes($_allFootnotesCollection)); - if (count($footnoteLinks) > 0) { - $objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteLinks)); + // Push to document.xml.rels + $sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); + // Add footnote media to package + $footnotesMedia = Media::getMediaElements('footnotes'); + if (!empty($footnotesMedia)) { + foreach ($footnotesMedia as $media) { + if ($media['type'] == 'image') { + $this->addFileToPackage($objZip, $media); + } + } + } + // Write footnotes.xml + $objZip->addFromString( + "word/footnotes.xml", + $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()) + ); + // Write footnotes.xml.rels + if (!empty($footnotesMedia)) { + $objZip->addFromString( + 'word/_rels/footnotes.xml.rels', + $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnotesMedia) + ); } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index b6e4c32c..7af96b03 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -90,12 +90,12 @@ class Base extends WriterPart $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { $this->writeLink($xmlWriter, $element, true); + } elseif ($element instanceof TextBreak) { + $xmlWriter->writeElement('w:br'); } elseif ($element instanceof Image) { $this->writeImage($xmlWriter, $element, true); } elseif ($element instanceof Footnote) { $this->writeFootnote($xmlWriter, $element, true); - } elseif ($element instanceof TextBreak) { - $xmlWriter->writeElement('w:br'); } } } @@ -434,6 +434,8 @@ class Base extends WriterPart $this->writeTextRun($xmlWriter, $element); } elseif ($element instanceof Link) { $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof PreserveText) { + $this->writePreserveText($xmlWriter, $element); } elseif ($element instanceof TextBreak) { $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof ListItem) { @@ -442,8 +444,6 @@ class Base extends WriterPart $this->writeImage($xmlWriter, $element); } elseif ($element instanceof Object) { $this->writeObject($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); } elseif ($element instanceof CheckBox) { $this->writeCheckBox($xmlWriter, $element); } @@ -493,7 +493,6 @@ class Base extends WriterPart $xmlWriter->endElement(); } } - $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:pict'); @@ -995,7 +994,6 @@ class Base extends WriterPart if ($margins) { $xmlWriter->startElement('w:tblCellMar'); if ($mTop) { - echo $margins[0]; $xmlWriter->startElement('w:top'); $xmlWriter->writeAttribute('w:w', $cellMargin[0]); $xmlWriter->writeAttribute('w:type', 'dxa'); diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index c4f8278f..b6e63628 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -10,23 +10,23 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\TOC; use PhpOffice\PhpWord\Container\Section; -use PhpOffice\PhpWord\Element\Footnote; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Object; -use PhpOffice\PhpWord\Element\PageBreak; -use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\Title; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Object; +use PhpOffice\PhpWord\Element\Footnote; use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\TOC; /** * Word2007 document part writer @@ -83,10 +83,10 @@ class Document extends Base $this->writeTextBreak($xmlWriter, $element); } elseif ($element instanceof PageBreak) { $this->writePageBreak($xmlWriter); - } elseif ($element instanceof Table) { - $this->writeTable($xmlWriter, $element); } elseif ($element instanceof ListItem) { $this->writeListItem($xmlWriter, $element); + } elseif ($element instanceof Table) { + $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { $this->writeImage($xmlWriter, $element); } elseif ($element instanceof Object) { diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 648d0864..0650d46a 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -127,12 +127,14 @@ class DocumentRels extends Base $relationType = $relation['type']; $relationName = $relation['target']; $relationId = $relation['rID']; + $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; $this->writeRelationship( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, - $relationName + $relationName, + $targetMode ); } diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index de2bf44d..cbcbcb26 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -9,13 +9,16 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Container\Footer as FooterElement; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -54,14 +57,20 @@ class Footer extends Base $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof Link) { + $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof PreserveText) { + $this->writePreserveText($xmlWriter, $element); } elseif ($element instanceof TextBreak) { $this->writeTextBreak($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); } elseif ($element instanceof Table) { $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { $this->writeImage($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); + } elseif ($element instanceof CheckBox) { + $this->writeCheckBox($xmlWriter, $element); } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index d8ba4352..628c1e35 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -12,6 +12,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Element\Footnote; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -34,17 +35,20 @@ class Footnotes extends Base // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('w:footnotes'); - $xmlWriter->writeAttribute( - 'xmlns:r', - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' - ); - $xmlWriter->writeAttribute( - 'xmlns:w', - 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' - ); + + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + // Separator and continuation separator $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', 0); + $xmlWriter->writeAttribute('w:id', -1); $xmlWriter->writeAttribute('w:type', 'separator'); $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); @@ -53,9 +57,8 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // w:footnote - // Content $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', 1); + $xmlWriter->writeAttribute('w:id', 0); $xmlWriter->writeAttribute('w:type', 'continuationSeparator'); $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); @@ -64,6 +67,7 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // w:footnote + // Content foreach ($allFootnotesCollection as $footnote) { if ($footnote instanceof Footnote) { $this->writeFootnote($xmlWriter, $footnote); @@ -113,6 +117,8 @@ class Footnotes extends Base $this->writeText($xmlWriter, $element, true); } elseif ($element instanceof Link) { $this->writeLink($xmlWriter, $element, true); + } elseif ($element instanceof Image) { + $this->writeImage($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 07a16ec7..7bd95ed6 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -9,13 +9,16 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Container\Header as HeaderElement; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Element\TextRun; +use PhpOffice\PhpWord\Element\Link; +use PhpOffice\PhpWord\Element\PreserveText; +use PhpOffice\PhpWord\Element\TextBreak; +use PhpOffice\PhpWord\Element\ListItem; +use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -47,7 +50,6 @@ class Header extends Base $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - $_elements = $header->getElements(); foreach ($_elements as $element) { @@ -55,8 +57,14 @@ class Header extends Base $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof Link) { + $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof PreserveText) { + $this->writePreserveText($xmlWriter, $element); } elseif ($element instanceof TextBreak) { $this->writeTextBreak($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); } elseif ($element instanceof Table) { $this->writeTable($xmlWriter, $element); } elseif ($element instanceof Image) { @@ -65,8 +73,8 @@ class Header extends Base } else { $this->writeWatermark($xmlWriter, $element); } - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); + } elseif ($element instanceof CheckBox) { + $this->writeCheckBox($xmlWriter, $element); } } diff --git a/tests/PhpWord/Tests/Element/Table/CellTest.php b/tests/PhpWord/Tests/Element/Table/CellTest.php index b8daca61..d16f275a 100644 --- a/tests/PhpWord/Tests/Element/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/Table/CellTest.php @@ -90,16 +90,6 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); } - /** - * Add link exception - * @expectedException \BadMethodCallException - */ - public function testAddLinkException() - { - $oCell = new Cell('header', 1); - $element = $oCell->addLink('http://google.com', 'Google'); - } - /** * Add text break */ diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index 5ea7ed80..ff74e992 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -27,9 +27,8 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $rIdFootnote = Footnote::addFootnoteElement($footnoteElement); $rIdLink = Footnote::addFootnoteLinkElement('http://test.com'); - $this->assertEquals(2, $rIdFootnote); + $this->assertEquals(1, $rIdFootnote); $this->assertEquals(1, $rIdLink); $this->assertEquals(1, count(Footnote::getFootnoteElements())); - $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 852cedb7..2d1434b3 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -43,7 +43,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $this->assertAttributeEquals( Media::getHeaderMediaElements(), - '_headerMedia', + 'headerMedia', 'PhpOffice\\PhpWord\\Media' ); } @@ -55,7 +55,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $this->assertAttributeEquals( Media::getFooterMediaElements(), - '_footerMedia', + 'footerMedia', 'PhpOffice\\PhpWord\\Media' ); } From 6f7b97e3ab562c1dbabc05d5a06bff4a1e426e20 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 1 Apr 2014 19:05:07 +0700 Subject: [PATCH 039/146] Add unit tests for refactoring results --- src/PhpWord/DocumentProperties.php | 12 ++++++------ src/PhpWord/Media.php | 2 +- tests/PhpWord/Tests/FootnoteTest.php | 1 + tests/PhpWord/Tests/MediaTest.php | 2 ++ tests/PhpWord/Tests/SettingsTest.php | 12 +++++++++++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 63ff0275..14ed3150 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -39,14 +39,14 @@ class DocumentProperties /** * Created * - * @var datetime|int + * @var int */ private $_created; /** * Modified * - * @var datetime|int + * @var int */ private $_modified; @@ -171,7 +171,7 @@ class DocumentProperties /** * Get Created * - * @return datetime + * @return int */ public function getCreated() { @@ -181,7 +181,7 @@ class DocumentProperties /** * Set Created * - * @param datetime $pValue + * @param int $pValue * @return \PhpOffice\PhpWord\DocumentProperties */ public function setCreated($pValue = null) @@ -196,7 +196,7 @@ class DocumentProperties /** * Get Modified * - * @return datetime + * @return int */ public function getModified() { @@ -206,7 +206,7 @@ class DocumentProperties /** * Set Modified * - * @param datetime $pValue + * @param int $pValue * @return \PhpOffice\PhpWord\DocumentProperties */ public function setModified($pValue = null) diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index c8b33301..dea9e1f3 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -202,7 +202,7 @@ class Media if (!empty(self::$media)) { foreach (self::$media as $key => $val) { if (substr($key, 0, 6) == $prefix) { - $mediaCollection[$key] = $val; + $mediaCollection[$key] = $val; } } } diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index ff74e992..955d02e5 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -30,5 +30,6 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, $rIdFootnote); $this->assertEquals(1, $rIdLink); $this->assertEquals(1, count(Footnote::getFootnoteElements())); + $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 2d1434b3..a3e6ead5 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -102,6 +102,8 @@ class MediaTest extends \PHPUnit_Framework_TestCase Media::addHeaderMediaElement(1, $remote, new Image($remote)); $this->assertEquals(2, Media::countHeaderMediaElements('header1')); + $this->assertEquals(2, count(Media::getMediaElements('header1'))); + $this->assertFalse(Media::getMediaElements('header2')); } /** diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index 543da143..fa78489e 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -19,7 +19,7 @@ use PhpOffice\PhpWord\Settings; class SettingsTest extends \PHPUnit_Framework_TestCase { /** - * Get and set compatibity option + * Get/set compatibity option */ public function testGetSetCompatibility() { @@ -28,4 +28,14 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertFalse(Settings::getCompatibility()); $this->assertFalse(Settings::setCompatibility('Non boolean')); } + + /** + * Get/set zip class + */ + public function testGetSetZipClass() + { + $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); + $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); + $this->assertFalse(Settings::setZipClass('foo')); + } } From 763de347df1aad981e98f041f46d71079955d37c Mon Sep 17 00:00:00 2001 From: Dave Gudgeon Date: Tue, 1 Apr 2014 13:25:05 +0100 Subject: [PATCH 040/146] Add support for document headers and footers to Template class. --- src/PhpWord/Template.php | 113 ++++++++++++++++-- tests/PhpWord/Tests/TemplateTest.php | 20 ++++ .../Tests/_files/templates/header-footer.docx | Bin 0 -> 4495 bytes 3 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 tests/PhpWord/Tests/_files/templates/header-footer.docx diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index f54d729e..e38e2a5a 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -32,6 +32,13 @@ class Template */ private $_tempFileName; + /** + * Document header XML + * + * @var string[] + */ + private $_headerXMLs = array(); + /** * Document XML * @@ -39,6 +46,12 @@ class Template */ private $_documentXML; + /** + * Document footer XML + * + * @var string[] + */ + private $_footerXMLs = array(); /** * Create a new Template Object @@ -62,9 +75,41 @@ class Template $this->_objZip = new $zipClass(); $this->_objZip->open($this->_tempFileName); + // Find and load up to three headers and footers + for ($i = 1; $i <= 3; $i++) { + $headerName = $this->getHeaderName($i); + $footerName = $this->getFooterName($i); + if ($this->_objZip->locateName($headerName) !== false) { + $this->_headerXMLs[$i] = $this->_objZip->getFromName($headerName); + } + if ($this->_objZip->locateName($footerName) !== false) { + $this->_footerXMLs[$i] = $this->_objZip->getFromName($footerName); + } + } + $this->_documentXML = $this->_objZip->getFromName('word/document.xml'); } + /** + * Get the name of the footer file for $index + * @param integer $index + * @return string + */ + private function getFooterName($index) + { + return sprintf('word/footer%d.xml', $index); + } + + /** + * Get the name of the header file for $index + * @param integer $index + * @return string + */ + private function getHeaderName($index) + { + return sprintf('word/header%d.xml', $index); + } + /** * Applies XSL style sheet to template's parts * @@ -97,20 +142,22 @@ class Template } /** - * Set a Template value + * Find and replace placeholders in the given XML section. * - * @param mixed $search + * @param string $documentPartXML + * @param string $search * @param mixed $replace * @param integer $limit + * @return string */ - public function setValue($search, $replace, $limit = -1) + protected function setValueForPart($documentPartXML, $search, $replace, $limit) { $pattern = '|\$\{([^\}]+)\}|U'; - preg_match_all($pattern, $this->_documentXML, $matches); + preg_match_all($pattern, $documentPartXML, $matches); foreach ($matches[0] as $value) { $valueCleaned = preg_replace('/<[^>]+>/', '', $value); $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); - $this->_documentXML = str_replace($value, $valueCleaned, $this->_documentXML); + $documentPartXML = str_replace($value, $valueCleaned, $documentPartXML); } if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { @@ -130,16 +177,58 @@ class Template $regExpDelim = '/'; $escapedSearch = preg_quote($search, $regExpDelim); - $this->_documentXML = preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $this->_documentXML, $limit); + return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); + } + + /** + * Set a Template value + * + * @param mixed $search + * @param mixed $replace + * @param integer $limit + */ + public function setValue($search, $replace, $limit = -1) + { + foreach ($this->_headerXMLs as $index => $headerXML) { + $this->_headerXMLs[$index] = $this->setValueForPart($this->_headerXMLs[$index], $search, $replace, $limit); + } + + $this->_documentXML = $this->setValueForPart($this->_documentXML, $search, $replace, $limit); + + foreach ($this->_footerXMLs as $index => $headerXML) { + $this->_footerXMLs[$index] = $this->setValueForPart($this->_footerXMLs[$index], $search, $replace, $limit); + } + } + + /** + * Find all variables in $documentPartXML + * @param string $documentPartXML + * @return string[] + */ + protected function getVariablesForPart($documentPartXML) + { + preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); + + return $matches[1]; } /** * Returns array of all variables in template + * @return string[] */ public function getVariables() { - preg_match_all('/\$\{(.*?)}/i', $this->_documentXML, $matches); - return $matches[1]; + $variables = $this->getVariablesForPart($this->_documentXML); + + foreach ($this->_headerXMLs as $headerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); + } + + foreach ($this->_footerXMLs as $footerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); + } + + return array_unique($variables); } /** @@ -251,8 +340,16 @@ class Template */ public function save() { + foreach ($this->_headerXMLs as $index => $headerXML) { + $this->_objZip->addFromString($this->getHeaderName($index), $this->_headerXMLs[$index]); + } + $this->_objZip->addFromString('word/document.xml', $this->_documentXML); + foreach ($this->_footerXMLs as $index => $headerXML) { + $this->_objZip->addFromString($this->getFooterName($index), $this->_footerXMLs[$index]); + } + // Close zip file if ($this->_objZip->close() === false) { throw new Exception('Could not close zip file.'); diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index 669ae946..848d7736 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -156,4 +156,24 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expectedVar, $actualVar); $this->assertTrue($docFound); } + + public function testVariablesCanBeReplacedInHeaderAndFooter() + { + $template = __DIR__ . "/_files/templates/header-footer.docx"; + $expectedVar = array('documentContent', 'headerValue', 'footerValue'); + $docName = 'header-footer-test-result.docx'; + + $document = new Template($template); + $actualVar = $document->getVariables(); + $document->setValue('headerValue', 'Header Value'); + $document->setValue('documentContent', 'Document text.'); + $document->setValue('footerValue', 'Footer Value'); + $document->saveAs($docName); + $docFound = file_exists($docName); + unlink($docName); + + $this->assertEquals($expectedVar, $actualVar); + $this->assertTrue($docFound); + + } } diff --git a/tests/PhpWord/Tests/_files/templates/header-footer.docx b/tests/PhpWord/Tests/_files/templates/header-footer.docx new file mode 100644 index 0000000000000000000000000000000000000000..647d52222d612ef33a0113e8ea3ad84ad3c96085 GIT binary patch literal 4495 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 Date: Tue, 1 Apr 2014 22:13:03 +0100 Subject: [PATCH 041/146] Load any number of headers and footers --- src/PhpWord/Template.php | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index e38e2a5a..7d933755 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -75,16 +75,17 @@ class Template $this->_objZip = new $zipClass(); $this->_objZip->open($this->_tempFileName); - // Find and load up to three headers and footers - for ($i = 1; $i <= 3; $i++) { - $headerName = $this->getHeaderName($i); - $footerName = $this->getFooterName($i); - if ($this->_objZip->locateName($headerName) !== false) { - $this->_headerXMLs[$i] = $this->_objZip->getFromName($headerName); - } - if ($this->_objZip->locateName($footerName) !== false) { - $this->_footerXMLs[$i] = $this->_objZip->getFromName($footerName); - } + // Find and load headers and footers + $i = 1; + while ($this->_objZip->locateName($this->getHeaderName($i)) !== false) { + $this->_headerXMLs[$i] = $this->_objZip->getFromName($this->getHeaderName($i)); + $i++; + } + + $i = 1; + while ($this->_objZip->locateName($this->getFooterName($i)) !== false) { + $this->_footerXMLs[$i] = $this->_objZip->getFromName($this->getFooterName($i)); + $i++; } $this->_documentXML = $this->_objZip->getFromName('word/document.xml'); From 495930be9d5abcacc86dcf9d81d709c0f310c9e1 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 2 Apr 2014 09:01:44 +0700 Subject: [PATCH 042/146] Add element availability matrix and enable `addObject` in footnote and textrun --- CHANGELOG.md | 8 + docs/elements.rst | 45 ++++ samples/Sample_04_Textrun.php | 2 + samples/Sample_06_Footnote.php | 4 +- src/PhpWord/Container/Container.php | 236 +++++++++++------- src/PhpWord/Container/Footer.php | 4 +- src/PhpWord/Container/Header.php | 4 +- src/PhpWord/Container/Section.php | 8 +- src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Element/Table/Cell.php | 8 +- src/PhpWord/Element/TextRun.php | 6 +- src/PhpWord/Media.php | 42 ++-- src/PhpWord/Writer/Word2007.php | 26 +- src/PhpWord/Writer/Word2007/Base.php | 128 +++++----- src/PhpWord/Writer/Word2007/ContentTypes.php | 1 - src/PhpWord/Writer/Word2007/DocumentRels.php | 59 +---- src/PhpWord/Writer/Word2007/Footnotes.php | 3 + src/PhpWord/Writer/Word2007/FootnotesRels.php | 18 +- src/PhpWord/Writer/Word2007/Rels.php | 6 +- 19 files changed, 330 insertions(+), 280 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f6ac85..8b81a016 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,19 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 - CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 - Link: Ability to add link in header/footer - @ivanlanin GH-187 +- Object: Ability to add object in textrun and footnote - @ivanlanin GH-187 ### Bugfixes - Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 +### Deprecated + +- `createTextRun` replaced by `addTextRun` +- `createFootnote` replaced by `addFootnote` +- `createHeader` replaced by `addHeader` +- `createFooter` replaced by `addFooter` + ### Miscellaneous - Documentation: Simplify page level docblock - @ivanlanin GH-179 diff --git a/docs/elements.rst b/docs/elements.rst index bded72b8..d1634bf4 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -3,6 +3,51 @@ Elements ======== +Below are the matrix of element availability in each container. The column shows +the containers while the rows lists the elements. + ++-----+---------------+---------+--------+--------+------+----------+----------+ +| Num | Element | Section | Header | Footer | Cell | Text Run | Footnote | ++=====+===============+=========+========+========+======+==========+==========+ +| 1 | Text | v | v | v | v | v | v | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 2 | Text Run | v | v | v | v | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 3 | Link | v | v | v | v | v | v | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 4 | Title | v | ? | ? | ? | ? | ? | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 5 | Preserve Text | ? | v | v | v\* | ? | ? | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 6 | Text Break | v | v | v | v | v | v | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 7 | Page Break | v | \- | \- | \- | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 8 | List | v | v | v | v | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 9 | Table | v | v | v | ? | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 10 | Image | v | v | v | v | v | v | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 11 | Watermark | \- | v | \- | \- | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 12 | Object | v | ? | ? | v | v | v | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 13 | TOC | v | \- | \- | \- | \- | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 14 | Footnote | v | \- | \- | v\*\*| v\*\* | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 15 | CheckBox | v | v | v | v | ? | ? | ++-----+---------------+---------+--------+--------+------+----------+----------+ + +Legend: + +- ``v`` Available +- ``v*`` Available only when inside header/footer +- ``v**`` Available only when inside section +- ``-`` Not available +- ``?`` Should be available + Texts ----- diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index d289457d..d95297b8 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -29,6 +29,8 @@ $textrun->addText(' Sample Link: '); $textrun->addLink('http://www.google.com', null, 'NLink'); $textrun->addText(' Sample Image: '); $textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$textrun->addText(' Sample Object: '); +$textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); // Save file diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index e35f5d6b..57421eff 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -27,8 +27,10 @@ $footnote->addTextBreak(); $footnote->addText('But you can insert a manual text break like above, '); $footnote->addText('links like '); $footnote->addLink('http://www.google.com', null, 'NLink'); -$footnote->addText(', or image like '); +$footnote->addText(', image like '); $footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$footnote->addText(', or object like '); +$footnote->addObject('resources/_sheet.xls'); $footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.'); diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index a29e393c..fd88955e 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -37,21 +37,21 @@ use PhpOffice\PhpWord\Element\CheckBox; abstract class Container { /** - * Container type section|header|footer + * Container type section|header|footer|cell|textrun|footnote * * @var string */ - protected $containerType; + protected $container; /** * Section Id * * @var int */ - protected $sectionId; + protected $containerId; /** - * Footer Element Collection + * Elements collection * * @var int */ @@ -62,11 +62,11 @@ abstract class Container * * Used by textrun and cell to determine where the element is located * because it will affect the availability of other element, e.g. footnote - * will not be available when $docPartType is header or footer. + * will not be available when $docPart is header or footer. * * @var string */ - protected $docPartType = null; + protected $docPart = null; /** * Document part Id @@ -92,9 +92,13 @@ abstract class Container */ public function addText($text, $fontStyle = null, $paragraphStyle = null) { - if (in_array($this->containerType, array('footnote', 'textrun'))) { + $this->checkValidity('text'); + + // Reset paragraph style for footnote and textrun. They have their own + if (in_array($this->container, array('footnote', 'textrun'))) { $paragraphStyle = null; } + $text = String::toUTF8($text); $element = new Text($text, $fontStyle, $paragraphStyle); $this->elements[] = $element; @@ -102,20 +106,6 @@ abstract class Container return $element; } - /** - * Add text break element - * - * @param int $count - * @param mixed $fontStyle - * @param mixed $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->elements[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - /** * Add textrun element * @@ -124,18 +114,17 @@ abstract class Container */ public function addTextRun($paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { - throw new \BadMethodCallException(); - } - if ($this->containerType == 'cell') { - $docPartType = $this->docPartType; + $this->checkValidity('textrun'); + + if ($this->container == 'cell') { + $docPart = $this->docPart; $docPartId = $this->docPartId; } else { - $docPartType = $this->containerType; - $docPartId = $this->sectionId; + $docPart = $this->container; + $docPartId = $this->containerId; } - $textRun = new TextRun($paragraphStyle, $docPartType, $docPartId); + $textRun = new TextRun($paragraphStyle, $docPart, $docPartId); $this->elements[] = $textRun; return $textRun; @@ -152,24 +141,30 @@ abstract class Container */ public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { - if (!is_null($this->docPartType)) { - $linkContainer = $this->docPartType; - $linkContainerId = $this->docPartId; + $this->checkValidity('link'); + + $inSection = true; + if (!is_null($this->docPart)) { + $container = $this->docPart; + $containerId = $this->docPartId; } else { - $linkContainer = $this->containerType; - $linkContainerId = $this->sectionId; + $container = $this->container; + $containerId = $this->containerId; } - if ($linkContainer == 'header' || $linkContainer == 'footer') { - $linkContainer .= $linkContainerId; + if ($container == 'header' || $container == 'footer') { + $container .= $containerId; + $inSection = false; + } elseif ($container == 'footnote') { + $inSection = false; } $linkSrc = String::toUTF8($linkSrc); $linkName = String::toUTF8($linkName); $link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle); - if ($linkContainer == 'section') { + if ($inSection) { $rID = Media::addSectionLinkElement($linkSrc); } else { - $rID = Media::addMediaElement($linkContainer, 'hyperlink', $linkSrc); + $rID = Media::addMediaElement($container, 'hyperlink', $linkSrc); } $link->setRelationId($rID); $this->elements[] = $link; @@ -183,13 +178,11 @@ abstract class Container * @param string $text * @param int $depth * @return Title - * @todo Enable title element in header, footer, footnote, textrun + * @todo Enable title element in other containers */ public function addTitle($text, $depth = 1) { - if (!in_array($this->containerType, array('section'))) { - throw new \BadMethodCallException(); - } + $this->checkValidity('title'); $text = String::toUTF8($text); $styles = Style::getStyles(); @@ -219,12 +212,7 @@ abstract class Container */ public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('header', 'footer', 'cell'))) { - throw new \BadMethodCallException(); - } - if ($this->containerType == 'cell' && $this->docPartType == 'section') { - throw new \BadMethodCallException(); - } + $this->checkValidity('preservetext'); $text = String::toUTF8($text); $ptext = new PreserveText($text, $fontStyle, $paragraphStyle); @@ -233,6 +221,22 @@ abstract class Container return $ptext; } + /** + * Add text break element + * + * @param int $count + * @param mixed $fontStyle + * @param mixed $paragraphStyle + */ + public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('textbreak'); + + for ($i = 1; $i <= $count; $i++) { + $this->elements[] = new TextBreak($fontStyle, $paragraphStyle); + } + } + /** * Add listitem element * @@ -242,13 +246,10 @@ abstract class Container * @param mixed $styleList * @param mixed $paragraphStyle * @return ListItem - * @todo Enable list item element in header and footer */ public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { - throw new \BadMethodCallException(); - } + $this->checkValidity('listitem'); $text = String::toUTF8($text); $listItem = new ListItem($text, $depth, $fontStyle, $styleList, $paragraphStyle); @@ -265,11 +266,9 @@ abstract class Container */ public function addTable($style = null) { - if (!in_array($this->containerType, array('section', 'header', 'footer'))) { - throw new \BadMethodCallException(); - } + $this->checkValidity('table'); - $table = new Table($this->containerType, $this->sectionId, $style); + $table = new Table($this->container, $this->containerId, $style); $this->elements[] = $table; return $table; @@ -285,30 +284,31 @@ abstract class Container */ public function addImage($src, $style = null, $isWatermark = false) { - if ($this->containerType == 'cell') { - $imageContainerType = $this->docPartType; - $imageContainerId = $this->docPartId; + $this->checkValidity('image'); + if ($this->container == 'cell' || $this->container == 'textrun') { + $container = $this->docPart; + $containerId = $this->docPartId; } else { - $imageContainerType = $this->containerType; - $imageContainerId = $this->sectionId; + $container = $this->container; + $containerId = $this->containerId; } $image = new Image($src, $style, $isWatermark); if (!is_null($image->getSource())) { $rID = null; - switch ($imageContainerType) { + switch ($container) { case 'textrun': case 'section': $rID = Media::addSectionMediaElement($src, 'image', $image); break; case 'header': - $rID = Media::addHeaderMediaElement($imageContainerId, $src, $image); + $rID = Media::addHeaderMediaElement($containerId, $src, $image); break; case 'footer': - $rID = Media::addFooterMediaElement($imageContainerId, $src, $image); + $rID = Media::addFooterMediaElement($containerId, $src, $image); break; case 'footnote': - $rID = Media::addMediaElement('footnotes', 'image', $src, $image); + $rID = Media::addMediaElement('footnote', 'image', $src, $image); break; } $image->setRelationId($rID); @@ -331,11 +331,19 @@ abstract class Container */ public function addObject($src, $style = null) { - if (!in_array($this->containerType, array('section', 'cell'))) { - throw new \BadMethodCallException(); + $inSection = true; + if (!is_null($this->docPart)) { + $container = $this->docPart; + $containerId = $this->docPartId; + } else { + $container = $this->container; + $containerId = $this->containerId; } - if ($this->containerType == 'cell' && $this->docPartType != 'section') { - throw new \BadMethodCallException(); + if ($container == 'header' || $container == 'footer') { + $container .= $containerId; + $inSection = false; + } elseif ($container == 'footnote') { + $inSection = false; } $object = new Object($src, $style); @@ -345,9 +353,14 @@ abstract class Container if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { $ext = substr($ext, 0, -1); } - $icon = __DIR__ . "/../_staticDocParts/_{$ext}.png"; - $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); - $data = Media::addSectionMediaElement($src, 'oleObject'); + $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); + if ($inSection) { + $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); + $data = Media::addSectionMediaElement($src, 'oleObject'); + } else { + $rIDimg = Media::addMediaElement($container, 'image', $icon, new Image($icon)); + $data = Media::addMediaElement($container, 'embeddings', $src); + } $rID = $data[0]; $objectId = $data[1]; $object->setRelationId($rID); @@ -368,12 +381,7 @@ abstract class Container */ public function addFootnote($paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'textrun', 'cell'))) { - throw new \BadMethodCallException(); - } - if (!is_null($this->docPartType) && $this->docPartType != 'section') { - throw new \BadMethodCallException(); - } + $this->checkValidity('footnote'); $footnote = new FootnoteElement($paragraphStyle); $refID = FootnoteCollection::addFootnoteElement($footnote); @@ -391,16 +399,10 @@ abstract class Container * @param mixed $fontStyle * @param mixed $paragraphStyle * @return CheckBox - * @todo Enable checkbox element in header and footer */ public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) { - if (!in_array($this->containerType, array('section', 'header', 'footer', 'cell'))) { - throw new \BadMethodCallException(); - } - if ($this->containerType == 'cell' && $this->docPartType != 'section') { - throw new \BadMethodCallException(); - } + $this->checkValidity('checkbox'); $name = String::toUTF8($name); $text = String::toUTF8($text); @@ -416,7 +418,7 @@ abstract class Container */ public function getSectionId() { - return $this->sectionId; + return $this->containerId; } /** @@ -436,10 +438,7 @@ abstract class Container */ public function getRelationId() { - if (!in_array($this->containerType, array('header', 'footer'))) { - throw new \BadMethodCallException(); - } - + $this->checkValidity('relationid'); return $this->relationId; } @@ -450,10 +449,7 @@ abstract class Container */ public function setRelationId($rId) { - if (!in_array($this->containerType, array('header', 'footer'))) { - throw new \BadMethodCallException(); - } - + $this->checkValidity('relationid'); $this->relationId = $rId; } @@ -490,4 +486,56 @@ abstract class Container { return $this->addFootnote($paragraphStyle); } + + /** + * Check if a method is allowed for the current container + * + * @param string $element + * @return boolean + */ + private function checkValidity($method) + { + $validContainers = array( + 'text' => 'all', + 'link' => 'all', + 'textbreak' => 'all', + 'image' => 'all', + 'textrun' => array('section', 'header', 'footer', 'cell'), + 'listitem' => array('section', 'header', 'footer', 'cell'), + 'checkbox' => array('section', 'header', 'footer', 'cell'), + 'table' => array('section', 'header', 'footer'), + 'object' => array('section', 'textrun', 'cell', 'footnote'), + 'footnote' => array('section', 'textrun', 'cell'), + 'preservetext' => array('header', 'footer', 'cell'), + 'relationid' => array('header', 'footer'), + 'title' => array('section'), + ); + $validContainerInContainers = array( + 'preservetext' => array(array('cell'), array('header', 'footer')), + 'object' => array(array('cell', 'textrun'), array('section')), + 'footnote' => array(array('cell', 'textrun'), array('section')), + ); + + // Check if a method is valid for current container + if (array_key_exists($method, $validContainers)) { + if (is_array($validContainers[$method])) { + if (!in_array($this->container, $validContainers[$method])) { + throw new \BadMethodCallException(); + } + } + } + // Check if a method is valid for current container, located in other container + if (array_key_exists($method, $validContainerInContainers)) { + $rules = $validContainerInContainers[$method]; + $containers = $rules[0]; + $allowedDocParts = $rules[1]; + foreach ($containers as $container) { + if ($this->container == $container && !in_array($this->docPart, $allowedDocParts)) { + throw new \BadMethodCallException(); + } + } + } + + return true; + } } diff --git a/src/PhpWord/Container/Footer.php b/src/PhpWord/Container/Footer.php index 37884b86..56f06383 100755 --- a/src/PhpWord/Container/Footer.php +++ b/src/PhpWord/Container/Footer.php @@ -21,7 +21,7 @@ class Footer extends Container */ public function __construct($sectionId) { - $this->containerType = 'footer'; - $this->sectionId = $sectionId; + $this->container = 'footer'; + $this->containerId = $sectionId; } } diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Container/Header.php index 3c702406..126f9198 100755 --- a/src/PhpWord/Container/Header.php +++ b/src/PhpWord/Container/Header.php @@ -40,8 +40,8 @@ class Header extends Container */ public function __construct($sectionId) { - $this->containerType = 'header'; - $this->sectionId = $sectionId; + $this->container = 'header'; + $this->containerId = $sectionId; } /** diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index dcef4707..b549280d 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -50,8 +50,8 @@ class Section extends Container */ public function __construct($sectionCount, $settings = null) { - $this->containerType = 'section'; - $this->sectionId = $sectionCount; + $this->container = 'section'; + $this->containerId = $sectionCount; $this->settings = new Settings(); $this->setSettings($settings); } @@ -112,7 +112,7 @@ class Section extends Container */ public function addHeader() { - $header = new Header($this->sectionId); + $header = new Header($this->containerId); $this->headers[] = $header; return $header; } @@ -124,7 +124,7 @@ class Section extends Container */ public function addFooter() { - $footer = new Footer($this->sectionId); + $footer = new Footer($this->containerId); $this->footer = $footer; return $footer; } diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index aa6af010..3d65a256 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -38,7 +38,7 @@ class Footnote extends Container */ public function __construct($paragraphStyle = null) { - $this->containerType = 'footnote'; + $this->container = 'footnote'; // Set paragraph style if (is_array($paragraphStyle)) { $this->paragraphStyle = new Paragraph(); diff --git a/src/PhpWord/Element/Table/Cell.php b/src/PhpWord/Element/Table/Cell.php index 3f795a28..2a15a263 100755 --- a/src/PhpWord/Element/Table/Cell.php +++ b/src/PhpWord/Element/Table/Cell.php @@ -34,15 +34,15 @@ class Cell extends Container /** * Create new instance * - * @param string $docPartType section|header|footer + * @param string $docPart section|header|footer * @param int $docPartId * @param int $width * @param array|CellStyle $style */ - public function __construct($docPartType, $docPartId, $width = null, $style = null) + public function __construct($docPart, $docPartId, $width = null, $style = null) { - $this->containerType = 'cell'; - $this->docPartType = $docPartType; + $this->container = 'cell'; + $this->docPart = $docPart; $this->docPartId = $docPartId; $this->width = $width; $this->cellStyle = new CellStyle(); diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 35701d45..5cf1a0c6 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -31,10 +31,10 @@ class TextRun extends Container * @param string $docPartType section|header|footer * @param int $docPartId */ - public function __construct($paragraphStyle = null, $docPartType = 'section', $docPartId = 1) + public function __construct($paragraphStyle = null, $docPart = 'section', $docPartId = 1) { - $this->containerType = 'textrun'; - $this->docPartType = $docPartType; + $this->container = 'textrun'; + $this->docPart = $docPart; $this->docPartId = $docPartId; // Set paragraph style if (is_array($paragraphStyle)) { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index dea9e1f3..ccfa1649 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -79,7 +79,7 @@ class Media $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); + $ext = $image->getImageExtension(); } if ($isMemImage) { $media['isMemImage'] = true; @@ -87,10 +87,10 @@ class Media $media['imagefunction'] = $image->getImageFunction(); } $folder = 'media'; - $file = $type . $cImg . '.' . strtolower($extension); + $file = $type . $cImg . '.' . strtolower($ext); } elseif ($type === 'oleObject') { $cObj++; - $folder = 'embedding'; + $folder = 'embeddings'; $file = $type . $cObj . '.bin'; } $media['source'] = $src; @@ -247,8 +247,8 @@ class Media /** * Add new media element * - * @param string $container section|header|footer|footnotes - * @param string $mediaType image|embedding|hyperlink + * @param string $container section|headerx|footerx|footnote + * @param string $mediaType image|embeddings|hyperlink * @param string $source * @param Image $image * @return int @@ -267,35 +267,49 @@ class Media $mediaTypeCount = self::countMediaElements($container, $mediaType); $mediaData = array(); $relId = $mediaCount + 1; + $target = null; $mediaTypeCount++; + + // Images if ($mediaType == 'image') { $isMemImage = false; if (!is_null($image)) { $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); + $ext = $image->getImageExtension(); + $ext = strtolower($ext); } if ($isMemImage) { $mediaData['isMemImage'] = true; $mediaData['createfunction'] = $image->getImageCreateFunction(); $mediaData['imagefunction'] = $image->getImageFunction(); } - $file = 'image' . $mediaTypeCount . '.' . strtolower($extension); - if ($container != 'footnotes') { - $file = $container . '_' . $file; - } - $target = 'media/' . $file; + $target = "media/{$container}_image{$mediaTypeCount}.{$ext}"; + // Objects + } elseif ($mediaType == 'embeddings') { + $file = "oleObject{$mediaTypeCount}.bin"; + $target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin"; + // Links } elseif ($mediaType == 'hyperlink') { $target = $source; } + $mediaData['source'] = $source; $mediaData['target'] = $target; $mediaData['type'] = $mediaType; $mediaData['rID'] = $relId; self::$media[$container][$mediaId] = $mediaData; - - return $relId; + if ($mediaType === 'embeddings') { + return array($relId, ++self::$objectId); + } else { + return $relId; + } } else { - return self::$media[$container][$mediaId]['rID']; + if ($mediaType === 'embeddings') { + $relId = self::$media[$container][$mediaId]['rID']; + return array($relId, ++self::$objectId); + } else { + return self::$media[$container][$mediaId]['rID']; + } } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index dd144da1..298b93cc 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -121,7 +121,7 @@ class Word2007 extends Writer implements IWriter $this->getWriterPart('documentrels')->writeHeaderFooterRels($hdrMedia) ); foreach ($hdrMedia as $element) { - if ($element['type'] == 'image') { + if ($element['type'] != 'hyperlink') { $this->addFileToPackage($objZip, $element); } } @@ -137,7 +137,7 @@ class Word2007 extends Writer implements IWriter $this->getWriterPart('documentrels')->writeHeaderFooterRels($ftrMedia) ); foreach ($ftrMedia as $element) { - if ($element['type'] == 'image') { + if ($element['type'] != 'hyperlink') { $this->addFileToPackage($objZip, $element); } } @@ -155,10 +155,10 @@ class Word2007 extends Writer implements IWriter foreach ($_headers as $index => &$_header) { $_cHdrs++; $_header->setRelationId(++$rID); - $hdrFile = 'header' . $_cHdrs . '.xml'; + $hdrFile = "header{$_cHdrs}.xml"; $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); $objZip->addFromString( - 'word/' . $hdrFile, + "word/{$hdrFile}", $this->getWriterPart('header')->writeHeader($_header) ); } @@ -167,10 +167,10 @@ class Word2007 extends Writer implements IWriter if (!is_null($_footer)) { $_footer->setRelationId(++$rID); $_footerCount = $_footer->getSectionId(); - $ftrFile = 'footer' . $_footerCount . '.xml'; + $ftrFile = "footer{$_footerCount}.xml"; $sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID); $objZip->addFromString( - 'word/' . $ftrFile, + "word/{$ftrFile}", $this->getWriterPart('footer')->writeFooter($_footer) ); } @@ -181,24 +181,24 @@ class Word2007 extends Writer implements IWriter // Push to document.xml.rels $sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); // Add footnote media to package - $footnotesMedia = Media::getMediaElements('footnotes'); - if (!empty($footnotesMedia)) { - foreach ($footnotesMedia as $media) { - if ($media['type'] == 'image') { + $footnoteMedia = Media::getMediaElements('footnote'); + if (!empty($footnoteMedia)) { + foreach ($footnoteMedia as $media) { + if ($media['type'] != 'hyperlink') { $this->addFileToPackage($objZip, $media); } } } // Write footnotes.xml $objZip->addFromString( - "word/footnotes.xml", + 'word/footnotes.xml', $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()) ); // Write footnotes.xml.rels - if (!empty($footnotesMedia)) { + if (!empty($footnoteMedia)) { $objZip->addFromString( 'word/_rels/footnotes.xml.rels', - $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnotesMedia) + $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteMedia) ); } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 7af96b03..d5c0160a 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -44,11 +44,8 @@ class Base extends WriterPart * @param Text $text * @param boolean $withoutP */ - protected function writeText( - XMLWriter $xmlWriter, - Text $text, - $withoutP = false - ) { + protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) + { $styleFont = $text->getFontStyle(); $styleParagraph = $text->getParagraphStyle(); $strText = htmlspecialchars($text->getText()); @@ -76,10 +73,8 @@ class Base extends WriterPart * @param XMLWriter $xmlWriter * @param TextRun $textrun */ - protected function writeTextRun( - XMLWriter $xmlWriter, - TextRun $textrun - ) { + protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) + { $elements = $textrun->getElements(); $styleParagraph = $textrun->getParagraphStyle(); $xmlWriter->startElement('w:p'); @@ -94,6 +89,8 @@ class Base extends WriterPart $xmlWriter->writeElement('w:br'); } elseif ($element instanceof Image) { $this->writeImage($xmlWriter, $element, true); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element, true); } elseif ($element instanceof Footnote) { $this->writeFootnote($xmlWriter, $element, true); } @@ -109,11 +106,8 @@ class Base extends WriterPart * @param Link $link * @param boolean $withoutP */ - protected function writeLink( - XMLWriter $xmlWriter, - Link $link, - $withoutP = false - ) { + protected function writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) + { $rID = $link->getRelationId(); $linkName = $link->getLinkName(); if (is_null($linkName)) { @@ -196,10 +190,8 @@ class Base extends WriterPart * @param XMLWriter $xmlWriter * @param PreserveText $textrun */ - protected function writePreserveText( - XMLWriter $xmlWriter, - PreserveText $textrun - ) { + protected function writePreserveText(XMLWriter $xmlWriter, PreserveText $textrun) + { $styleFont = $textrun->getFontStyle(); $styleParagraph = $textrun->getParagraphStyle(); @@ -467,11 +459,8 @@ class Base extends WriterPart * @param Image $image * @param boolean $withoutP */ - protected function writeImage( - XMLWriter $xmlWriter, - Image $image, - $withoutP = false - ) { + protected function writeImage(XMLWriter $xmlWriter, Image $image, $withoutP = false) + { $rId = $image->getRelationId(); $style = $image->getStyle(); @@ -601,8 +590,9 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param Object $object + * @param boolean $withoutP */ - protected function writeObject(XMLWriter $xmlWriter, Object $object) + protected function writeObject(XMLWriter $xmlWriter, Object $object, $withoutP = false) { $rIdObject = $object->getRelationId(); $rIdImage = $object->getImageRelationId(); @@ -611,7 +601,9 @@ class Base extends WriterPart $style = $object->getStyle(); $align = $style->getAlign(); - $xmlWriter->startElement('w:p'); + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + } if (!is_null($align)) { $xmlWriter->startElement('w:pPr'); $xmlWriter->startElement('w:jc'); @@ -643,7 +635,9 @@ class Base extends WriterPart $xmlWriter->endElement(); // o:OLEObject $xmlWriter->endElement(); // w:object $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:p + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } } /** @@ -653,11 +647,8 @@ class Base extends WriterPart * @param Footnote $footnote * @param boolean $withoutP */ - protected function writeFootnote( - XMLWriter $xmlWriter, - Footnote $footnote, - $withoutP = false - ) { + protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) + { if (!$withoutP) { $xmlWriter->startElement('w:p'); } @@ -682,12 +673,8 @@ class Base extends WriterPart * @param boolean $withoutP * @param boolean $checkState */ - protected function writeCheckBox( - XMLWriter $xmlWriter, - CheckBox $checkbox, - $withoutP = false, - $checkState = false - ) { + protected function writeCheckBox(XMLWriter $xmlWriter, CheckBox $checkbox, $withoutP = false, $checkState = false) + { $name = htmlspecialchars($checkbox->getName()); $name = String::controlCharacterPHP2OOXML($name); $text = htmlspecialchars($checkbox->getText()); @@ -758,11 +745,8 @@ class Base extends WriterPart * @param Paragraph $style * @param bool $withoutPPR */ - protected function writeParagraphStyle( - XMLWriter $xmlWriter, - Paragraph $style, - $withoutPPR = false - ) { + protected function writeParagraphStyle(XMLWriter $xmlWriter, Paragraph $style, $withoutPPR = false) + { $align = $style->getAlign(); $spacing = $style->getSpacing(); @@ -965,11 +949,8 @@ class Base extends WriterPart * @param TableStyle $style * @param boolean $isFullStyle */ - protected function writeTableStyle( - XMLWriter $xmlWriter, - TableStyle $style, - $isFullStyle = true - ) { + protected function writeTableStyle(XMLWriter $xmlWriter, TableStyle $style, $isFullStyle = true) + { $bgColor = $style->getBgColor(); $brdCol = $style->getBorderColor(); @@ -1094,11 +1075,8 @@ class Base extends WriterPart * @param string $type * @param TableStyle $style */ - protected function writeRowStyle( - XMLWriter $xmlWriter, - $type, - TableStyle $style - ) { + protected function writeRowStyle(XMLWriter $xmlWriter, $type, TableStyle $style) + { $brdSz = $style->getBorderSize(); $brdCol = $style->getBorderColor(); $bgColor = $style->getBgColor(); @@ -1265,6 +1243,26 @@ class Base extends WriterPart } } + /** + * Write media rels (image, embeddings, hyperlink) + * + * @param XMLWriter $xmlWriter + * @param array mediaRels + */ + protected function writeMediaRels(XMLWriter $xmlWriter, $mediaRels) + { + $rTypePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; + foreach ($mediaRels as $mediaRel) { + $rId = $mediaRel['rID']; + $rType = $mediaRel['type']; + $rName = $mediaRel['target']; // file name + $targetMode = ($rType == 'hyperlink') ? 'External' : ''; + $rType = $rTypePrefix . ($rType == 'embeddings' ? 'oleObject' : $rType); + $this->writeRel($xmlWriter, $rId, $rType, $rName, $targetMode); + } + + } + /** * Write individual rels entry * @@ -1274,28 +1272,19 @@ class Base extends WriterPart * @param string $pTarget Relationship target * @param string $pTargetMode Relationship target mode */ - protected function writeRelationship( - XMLWriter $xmlWriter, - $pId = 1, - $pType = '', - $pTarget = '', - $pTargetMode = '' - ) { + protected function writeRel(XMLWriter $xmlWriter, $pId, $pType, $pTarget, $pTargetMode = '') + { if ($pType != '' && $pTarget != '') { if (strpos($pId, 'rId') === false) { $pId = 'rId' . $pId; } - - // Write relationship $xmlWriter->startElement('Relationship'); $xmlWriter->writeAttribute('Id', $pId); $xmlWriter->writeAttribute('Type', $pType); $xmlWriter->writeAttribute('Target', $pTarget); - if ($pTargetMode != '') { $xmlWriter->writeAttribute('TargetMode', $pTargetMode); } - $xmlWriter->endElement(); } else { throw new Exception("Invalid parameters passed."); @@ -1309,11 +1298,8 @@ class Base extends WriterPart * @param Paragraph|string $styleParagraph * @param boolean $withoutPPR */ - protected function writeInlineParagraphStyle( - XMLWriter $xmlWriter, - $styleParagraph = null, - $withoutPPR = false - ) { + protected function writeInlineParagraphStyle(XMLWriter $xmlWriter, $styleParagraph = null, $withoutPPR = false) + { if ($styleParagraph instanceof Paragraph) { $this->writeParagraphStyle($xmlWriter, $styleParagraph, $withoutPPR); } else { @@ -1337,10 +1323,8 @@ class Base extends WriterPart * @param XMLWriter $xmlWriter * @param Font|string $styleFont */ - protected function writeInlineFontStyle( - XMLWriter $xmlWriter, - $styleFont = null - ) { + protected function writeInlineFontStyle(XMLWriter $xmlWriter, $styleFont = null) + { if ($styleFont instanceof Font) { $this->writeFontStyle($xmlWriter, $styleFont); } else { diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 98121133..86689823 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -151,7 +151,6 @@ class ContentTypes extends WriterPart } } - $xmlWriter->endElement(); // Return diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 0650d46a..d39527a9 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -35,7 +35,7 @@ class DocumentRels extends Base $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Relationship word/document.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', @@ -43,7 +43,7 @@ class DocumentRels extends Base ); // Relationship word/numbering.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 2, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering', @@ -51,7 +51,7 @@ class DocumentRels extends Base ); // Relationship word/settings.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 3, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings', @@ -59,7 +59,7 @@ class DocumentRels extends Base ); // Relationship word/settings.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 4, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', @@ -67,7 +67,7 @@ class DocumentRels extends Base ); // Relationship word/settings.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 5, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings', @@ -75,73 +75,34 @@ class DocumentRels extends Base ); // Relationship word/settings.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, 6, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable', 'fontTable.xml' ); - // Relationships to Images / Embeddings / Headers / Footers - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - - $this->writeRelationship( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, - $relationName, - $targetMode - ); - } - - - $xmlWriter->endElement(); + $this->writeMediaRels($xmlWriter, $_relsCollection); + $xmlWriter->endElement(); // Relationships // Return return $xmlWriter->getData(); } /** - * Write header footer rels + * Write header footer rels word/_rels/*.xml.rels * * @param array $_relsCollection */ public function writeHeaderFooterRels($_relsCollection) { - // Create XML writer $xmlWriter = $this->getXmlWriter(); - - // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Relationships to Images / Embeddings / Headers / Footers - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - - $this->writeRelationship( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, - $relationName, - $targetMode - ); - } - - + $this->writeMediaRels($xmlWriter, $_relsCollection); $xmlWriter->endElement(); - // Return return $xmlWriter->getData(); } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 628c1e35..9ae7473a 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -13,6 +13,7 @@ use PhpOffice\PhpWord\Element\Footnote; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Element\Object; use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -119,6 +120,8 @@ class Footnotes extends Base $this->writeLink($xmlWriter, $element, true); } elseif ($element instanceof Image) { $this->writeImage($xmlWriter, $element, true); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element, true); } elseif ($element instanceof TextBreak) { $xmlWriter->writeElement('w:br'); } diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index 405df69f..49ca2181 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -24,29 +24,13 @@ class FootnotesRels extends Base */ public function writeFootnotesRels($_relsCollection) { - // Create XML writer $xmlWriter = $this->getXmlWriter(); - - // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Relationships to Links - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - - $this->writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); - } - + $this->writeMediaRels($xmlWriter, $_relsCollection); $xmlWriter->endElement(); - // Return return $xmlWriter->getData(); } } diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index a675057f..5619d978 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -38,7 +38,7 @@ class Rels extends Base $relationId = 1; // Relationship word/document.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', @@ -46,7 +46,7 @@ class Rels extends Base ); // Relationship docProps/core.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', @@ -54,7 +54,7 @@ class Rels extends Base ); // Relationship docProps/app.xml - $this->writeRelationship( + $this->writeRel( $xmlWriter, ++$relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', From a2a00393c18f781fdc1ace92871ed0b2a2d74e34 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 2 Apr 2014 10:37:27 +0700 Subject: [PATCH 043/146] Remove HashTable and all related properties/methods. PHPWord doesn't (yet) need it. --- CHANGELOG.md | 1 + src/PhpWord/HashTable.php | 203 ---------------------- src/PhpWord/Writer/ODText.php | 56 ------ src/PhpWord/Writer/ODText/Manifest.php | 28 +-- src/PhpWord/Writer/RTF.php | 21 --- tests/PhpWord/Tests/Writer/ODTextTest.php | 1 - tests/PhpWord/Tests/Writer/RTFTest.php | 1 - 7 files changed, 2 insertions(+), 309 deletions(-) delete mode 100644 src/PhpWord/HashTable.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b81a016..84952a3c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Reader: Rename AbstractReader > Reader - @ivanlanin - General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187 - Container: Create new Container abstract class - @ivanlanin GH-187 +- General: Remove legacy HashTable and all related properties/methods - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/HashTable.php b/src/PhpWord/HashTable.php deleted file mode 100644 index 93bcb689..00000000 --- a/src/PhpWord/HashTable.php +++ /dev/null @@ -1,203 +0,0 @@ -addFromSource($pSource); - } - } - - /** - * Add HashTable items from source - * - * @param \PhpOffice\PhpWord\IComparable[] $pSource Source array to create HashTable from - * @throws \PhpOffice\PhpWord\Exception\Exception - */ - public function addFromSource($pSource = null) - { - // Check if an array was passed - if ($pSource == null) { - return; - } elseif (!is_array($pSource)) { - throw new Exception('Invalid array parameter passed.'); - } - - foreach ($pSource as $item) { - $this->add($item); - } - } - - /** - * Add HashTable item - * - * @param \PhpOffice\PhpWord\IComparable $pSource Item to add - */ - public function add(IComparable $pSource = null) - { - // Determine hashcode - $hashCode = null; - $hashIndex = $pSource->getHashIndex(); - if (is_null($hashIndex)) { - $hashCode = $pSource->getHashCode(); - } elseif (isset ($this->_keyMap[$hashIndex])) { - $hashCode = $this->_keyMap[$hashIndex]; - } else { - $hashCode = $pSource->getHashCode(); - } - - // Add value - if (!isset($this->_items[$hashCode])) { - $this->_items[$hashCode] = $pSource; - $index = count($this->_items) - 1; - $this->_keyMap[$index] = $hashCode; - $pSource->setHashIndex($index); - } else { - $pSource->setHashIndex($this->_items[$hashCode]->getHashIndex()); - } - } - - /** - * Remove HashTable item - * - * @param \PhpOffice\PhpWord\IComparable $pSource Item to remove - */ - public function remove(IComparable $pSource = null) - { - if (isset($this->_items[$pSource->getHashCode()])) { - unset($this->_items[$pSource->getHashCode()]); - - $deleteKey = -1; - foreach ($this->_keyMap as $key => $value) { - if ($deleteKey >= 0) { - $this->_keyMap[$key - 1] = $value; - } - - if ($value == $pSource->getHashCode()) { - $deleteKey = $key; - } - } - unset($this->_keyMap[count($this->_keyMap) - 1]); - } - } - - /** - * Clear HashTable - * - */ - public function clear() - { - $this->_items = array(); - $this->_keyMap = array(); - } - - /** - * Get item count - * - * @return int - */ - public function count() - { - return count($this->_items); - } - - /** - * Get hash code index - * - * @param string $pHashCode - * @return int Index - */ - public function getIndexForHashCode($pHashCode = '') - { - return array_search($pHashCode, $this->_keyMap); - } - - /** - * Get by index - * - * @param int $pIndex - * @return \PhpOffice\PhpWord\IComparable - */ - public function getByIndex($pIndex = 0) - { - if (isset($this->_keyMap[$pIndex])) { - return $this->getByHashCode($this->_keyMap[$pIndex]); - } - - return null; - } - - /** - * Get by hashcode - * @param string $pHashCode - * @return \PhpOffice\PhpWord\IComparable - * - */ - public function getByHashCode($pHashCode = '') - { - if (isset($this->_items[$pHashCode])) { - return $this->_items[$pHashCode]; - } - - return null; - } - - /** - * Convert to array - * - * @return \PhpOffice\PhpWord\IComparable[] - */ - public function toArray() - { - return $this->_items; - } - - /** - * Implement PHP __clone to create a deep clone, not just a shallow copy. - */ - public function __clone() - { - $vars = get_object_vars($this); - foreach ($vars as $key => $value) { - if (is_object($value)) { - $this->$key = clone $value; - } - } - } -} diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 72955ef1..04ec0bec 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -11,7 +11,6 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\HashTable; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\ODText\Content; use PhpOffice\PhpWord\Writer\ODText\Manifest; @@ -24,12 +23,6 @@ use PhpOffice\PhpWord\Writer\ODText\Styles; */ class ODText extends Writer implements IWriter { - /** - * Private unique PHPWord_Worksheet_BaseDrawing HashTable - * - * @var HashTable - */ - private $drawingHashTable; /** * Create new ODText writer @@ -49,9 +42,6 @@ class ODText extends Writer implements IWriter foreach ($this->writerParts as $writer) { $writer->setParentWriter($this); } - - // Set HashTable variables - $this->drawingHashTable = new HashTable(); } /** @@ -103,42 +93,6 @@ class ODText extends Writer implements IWriter // Add META-INF/manifest.xml $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->phpWord)); - // Add media. Has not used yet. Legacy from PHPExcel. - // @codeCoverageIgnoreStart - for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { - if ($this->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { - $imageContents = null; - $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath(); - - if (strpos($imagePath, 'zip://') !== false) { - $imagePath = substr($imagePath, 6); - $imagePathSplitted = explode('#', $imagePath); - - $zipClass = Settings::getZipClass(); - $imageZip = new $zipClass(); - $imageZip->open($imagePathSplitted[0]); - $imageContents = $imageZip->getFromName($imagePathSplitted[1]); - $imageZip->close(); - unset($imageZip); - } else { - $imageContents = file_get_contents($imagePath); - } - - $objZip->addFromString('Pictures/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); - } elseif ($this->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_MemoryDrawing) { - ob_start(); - call_user_func( - $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(), - $this->getDrawingHashTable()->getByIndex($i)->getImageResource() - ); - $imageContents = ob_get_contents(); - ob_end_clean(); - - $objZip->addFromString('Pictures/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); - } - } - // @codeCoverageIgnoreEnd - // Close file if ($objZip->close() === false) { throw new Exception("Could not close zip file $pFilename."); @@ -149,14 +103,4 @@ class ODText extends Writer implements IWriter throw new Exception("PhpWord object unassigned."); } } - - /** - * Get PHPWord_Worksheet_BaseDrawing HashTable - * - * @return HashTable - */ - public function getDrawingHashTable() - { - return $this->drawingHashTable; - } } diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 69949c73..d7ab6cdc 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -59,33 +59,7 @@ class Manifest extends WriterPart $xmlWriter->writeAttribute('manifest:full-path', 'styles.xml'); $xmlWriter->endElement(); - // Not used yet. Legacy from PHPExcel - // @codeCoverageIgnoreStart - for ($i = 0; $i < $this->getParentWriter()->getDrawingHashTable()->count(); ++$i) { - if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { - $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension()); - $mimeType = $this->getImageMimeType($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath()); - - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', $mimeType); - $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); - $xmlWriter->endElement(); - } elseif ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_MemoryDrawing) { - $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType()); - $extension = explode('/', $extension); - $extension = $extension[1]; - - $mimeType = $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType(); - - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', $mimeType); - $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); - $xmlWriter->endElement(); - } - } - // @codeCoverageIgnoreEnd - - $xmlWriter->endElement(); + $xmlWriter->endElement(); // manifest:manifest // Return return $xmlWriter->getData(); diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index b5ce20a7..6d693f17 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -11,7 +11,6 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\HashTable; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\ListItem; @@ -33,13 +32,6 @@ use PhpOffice\PhpWord\TOC; */ class RTF extends Writer implements IWriter { - /** - * Private unique PHPWord_Worksheet_BaseDrawing HashTable - * - * @var HashTable - */ - private $drawingHashTable; - /** * Color register * @@ -69,9 +61,6 @@ class RTF extends Writer implements IWriter { // Assign PhpWord $this->setPhpWord($phpWord); - - // Set HashTable variables - $this->drawingHashTable = new HashTable(); } /** @@ -95,16 +84,6 @@ class RTF extends Writer implements IWriter } } - /** - * Get PHPWord_Worksheet_BaseDrawing HashTable - * - * @return HashTable - */ - public function getDrawingHashTable() - { - return $this->drawingHashTable; - } - /** * Get all data * diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 9ee31432..82263c0f 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -26,7 +26,6 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $object = new ODText(new PhpWord()); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\HashTable', $object->getDrawingHashTable()); $this->assertEquals('./', $object->getDiskCachingDirectory()); foreach (array('Content', 'Manifest', 'Meta', 'Mimetype', 'Styles') as $part) { diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 4016cb85..4872ef39 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -26,7 +26,6 @@ class RTFTest extends \PHPUnit_Framework_TestCase $object = new RTF(new PhpWord); $this->assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\HashTable', $object->getDrawingHashTable()); } /** From f0ee25f3437fd8101d55c2afe8372ab62133fc99 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 2 Apr 2014 11:02:56 +0700 Subject: [PATCH 044/146] Deprecate `createSection` in favor of `addSection` --- CHANGELOG.md | 1 + README.md | 2 +- docs/containers.rst | 18 ++++----- docs/elements.rst | 24 +++++------ docs/general.rst | 4 +- samples/Sample_01_SimpleText.php | 2 +- samples/Sample_02_TabStops.php | 2 +- samples/Sample_03_Sections.php | 12 +++--- samples/Sample_04_Textrun.php | 4 +- samples/Sample_05_Multicolumn.php | 10 ++--- samples/Sample_06_Footnote.php | 8 ++-- samples/Sample_08_ParagraphPagination.php | 2 +- samples/Sample_09_Tables.php | 2 +- samples/Sample_10_EastAsianFontStyle.php | 2 +- samples/Sample_12_HeaderFooter.php | 12 +++--- samples/Sample_13_Images.php | 2 +- samples/Sample_14_ListItem.php | 2 +- samples/Sample_15_Link.php | 2 +- samples/Sample_16_Object.php | 2 +- samples/Sample_17_TitleTOC.php | 2 +- samples/Sample_18_Watermark.php | 4 +- samples/Sample_19_TextBreak.php | 2 +- samples/Sample_20_BGColor.php | 2 +- samples/Sample_21_TableRowRules.php | 2 +- samples/Sample_22_CheckBox.php | 2 +- src/PhpWord/PhpWord.php | 27 +++++++++---- src/PhpWord/Reader/Word2007.php | 4 +- tests/PhpWord/Tests/Container/FooterTest.php | 2 +- tests/PhpWord/Tests/Container/HeaderTest.php | 2 +- tests/PhpWord/Tests/Container/SectionTest.php | 4 +- .../PhpWord/Tests/Element/Table/CellTest.php | 2 +- tests/PhpWord/Tests/Element/TextRunTest.php | 2 +- tests/PhpWord/Tests/PhpWordTest.php | 4 +- tests/PhpWord/Tests/Style/FontTest.php | 2 +- tests/PhpWord/Tests/Style/ParagraphTest.php | 2 +- .../Tests/Writer/ODText/ContentTest.php | 4 +- tests/PhpWord/Tests/Writer/ODTextTest.php | 8 ++-- tests/PhpWord/Tests/Writer/RTFTest.php | 8 ++-- .../Tests/Writer/Word2007/BaseTest.php | 40 +++++++++---------- .../Tests/Writer/Word2007/DocumentTest.php | 8 ++-- .../Tests/Writer/Word2007/FooterTest.php | 2 +- .../Tests/Writer/Word2007/FootnotesTest.php | 6 +-- .../Tests/Writer/Word2007/HeaderTest.php | 2 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 20 +++++----- 44 files changed, 145 insertions(+), 131 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84952a3c..28b6326b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - `createFootnote` replaced by `addFootnote` - `createHeader` replaced by `addHeader` - `createFooter` replaced by `addFooter` +- `createSection` replaced by `addSection` ### Miscellaneous diff --git a/README.md b/README.md index 8d5370eb..95d5947e 100755 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Every element you want to append to the word document is placed in a section. // To create a basic section: -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // After creating a section, you can append elements: $section->addText('Hello world!'); diff --git a/docs/containers.rst b/docs/containers.rst index dc8f2f9a..53579537 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -16,7 +16,7 @@ section, use the following code: .. code-block:: php - $section = $phpWord->createSection($sectionSettings); + $section = $phpWord->addSection($sectionSettings); The ``$sectionSettings`` is an optional associative array that sets the section. Example: @@ -70,10 +70,10 @@ property of the section. .. code-block:: php // Method 1 - $section = $phpWord->createSection(array('pageNumberingStart' => 1)); + $section = $phpWord->addSection(array('pageNumberingStart' => 1)); // Method 2 - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->getSettings()->setPageNumberingStart(1); Multicolumn @@ -85,10 +85,10 @@ using the ``breakType`` and ``colsNum`` property of the section. .. code-block:: php // Method 1 - $section = $phpWord->createSection(array('breakType' => 'continuous', 'colsNum' => 2)); + $section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2)); // Method 2 - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->getSettings()->setBreakType('continuous'); $section->getSettings()->setColsNum(2); @@ -96,11 +96,11 @@ Headers ------- Each section can have its own header reference. To create a header use -the ``createHeader`` method: +the ``addHeader`` method: .. code-block:: php - $header = $section->createHeader(); + $header = $section->addHeader(); Be sure to save the result in a local object. You can use all elements that are available for the footer. See "Footer" section for detail. @@ -111,11 +111,11 @@ Footers ------- Each section can have its own footer reference. To create a footer, use -the ``createFooter`` method: +the ``addFooter`` method: .. code-block:: php - $footer = $section->createFooter(); + $footer = $section->addFooter(); Be sure to save the result in a local object to add elements to a footer. You can add the following elements to footers: diff --git a/docs/elements.rst b/docs/elements.rst index d1634bf4..da2038e5 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -51,9 +51,9 @@ Legend: Texts ----- -Text can be added by using ``addText`` and ``createTextRun`` method. +Text can be added by using ``addText`` and ``addTextRun`` method. ``addText`` is used for creating simple paragraphs that only contain -texts with the same style. ``createTextRun`` is used for creating +texts with the same style. ``addTextRun`` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: @@ -61,7 +61,7 @@ syntaxes are as follow: .. code-block:: php $section->addText($text, [$fontStyle], [$paragraphStyle]); - $textrun = $section->createTextRun([$paragraphStyle]); + $textrun = $section->addTextRun([$paragraphStyle]); Text styles ~~~~~~~~~~~ @@ -79,7 +79,7 @@ Inline style examples: $paragraphStyle = array('align' => 'both'); $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addText('I am bold', array('bold' => true)); $textrun->addText('I am italic', array('italic' => true)); $textrun->addText('I am colored, array('color' => 'AACC00')); @@ -300,7 +300,7 @@ Examples: .. code-block:: php - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addImage( 'mars.jpg', array( @@ -311,9 +311,9 @@ Examples: 'wrappingStyle' => 'behind' ) ); - $footer = $section->createFooter(); + $footer = $section->addFooter(); $footer->addImage('http://example.com/image.php'); - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg'); Image styles @@ -338,8 +338,8 @@ header reference. After creating a header, you can use the .. code-block:: php - $section = $phpWord->createSection(); - $header = $section->createHeader(); + $section = $phpWord->addSection(); + $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); Objects @@ -380,9 +380,9 @@ On textrun: .. code-block:: php - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addText('Lead text.'); - $footnote = $textrun->createFootnote(); + $footnote = $textrun->addFootnote(); $footnote->addText('Footnote text can have '); $footnote->addLink('http://test.com', 'links'); $footnote->addText('.'); @@ -395,7 +395,7 @@ On text: .. code-block:: php $section->addText('Lead text.'); - $footnote = $section->createFootnote(); + $footnote = $section->addFootnote(); $footnote->addText('Footnote text.'); The footnote reference number will be displayed with decimal number starting diff --git a/docs/general.rst b/docs/general.rst index 1c810722..e1545a04 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -19,7 +19,7 @@ folder `__. // Every element you want to append to the word document is placed in a section. // To create a basic section: - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // After creating a section, you can append elements: $section->addText('Hello world!'); @@ -136,7 +136,7 @@ points to twips. 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(6)) ); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $sectionStyle = $section->getSettings(); // half inch left margin $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 7ada399a..4405eaeb 100755 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -9,7 +9,7 @@ $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'spaceAfter' => $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Simple text $section->addTitle('Welcome to PhpWord', 1); diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index f08f1e15..01dc7617 100755 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -25,7 +25,7 @@ $phpWord->addParagraphStyle('centerTab', array( )); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add listitem elements $section->addText("Multiple Tabs:\tOne\tTwo\tThree", NULL, 'multipleTab'); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index c16b73db..7289fef0 100755 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -6,24 +6,24 @@ echo date('H:i:s') , ' Create new PhpWord object' , \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section -$section = $phpWord->createSection(array('borderColor' => '00FF00', 'borderSize' => 12)); +$section = $phpWord->addSection(array('borderColor' => '00FF00', 'borderSize' => 12)); $section->addText('I am placed on a default section.'); // New landscape section -$section = $phpWord->createSection(array('orientation' => 'landscape')); +$section = $phpWord->addSection(array('orientation' => 'landscape')); $section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.'); $section->addPageBreak(); $section->addPageBreak(); // New portrait section -$section = $phpWord->createSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); +$section = $phpWord->addSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); $section->addText('This section uses other margins.'); // New portrait section with Header & Footer -$section = $phpWord->createSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); +$section = $phpWord->addSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); $section->addText('This section and we play with header/footer height.'); -$section->createHeader()->addText('Header'); -$section->createFooter()->addText('Footer'); +$section->addHeader()->addText('Header'); +$section->addFooter()->addText('Footer'); // Save file $name = basename(__FILE__, '.php'); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index d95297b8..6c13a84f 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -12,10 +12,10 @@ $phpWord->addFontStyle('ColoredText', array('color'=>'FF8080')); $phpWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add text run -$textrun = $section->createTextRun('pStyle'); +$textrun = $section->addTextRun('pStyle'); $textrun->addText('Each textrun can contain native text, link elements or an image.'); $textrun->addText(' No break is placed after adding an element.', 'BoldText'); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 541e2e8a..4d81766e 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -10,29 +10,29 @@ $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Suspendisse congue congue leo sed pellentesque.'; // Normal -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Normal paragraph. ' . $filler); // Two columns -$section = $phpWord->createSection(array( +$section = $phpWord->addSection(array( 'colsNum' => 2, 'colsSpace' => 1440, 'breakType' => 'continuous')); $section->addText('Three columns, one inch (1440 twips) spacing. ' . $filler); // Normal -$section = $phpWord->createSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again. ' . $filler); // Three columns -$section = $phpWord->createSection(array( +$section = $phpWord->addSection(array( 'colsNum' => 3, 'colsSpace' => 720, 'breakType' => 'continuous')); $section->addText('Three columns, half inch (720 twips) spacing. ' . $filler); // Normal -$section = $phpWord->createSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again.'); // Save file diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 57421eff..270573d9 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -7,7 +7,7 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); \PhpOffice\PhpWord\Settings::setCompatibility(false); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add style definitions $phpWord->addParagraphStyle('pStyle', array('spacing'=>100)); @@ -16,10 +16,10 @@ $phpWord->addFontStyle('ColoredText', array('color'=>'FF8080')); $phpWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); // Add text elements -$textrun = $section->createTextRun('pStyle'); +$textrun = $section->addTextRun('pStyle'); $textrun->addText('This is some lead text in a paragraph with a following footnote. ','pStyle'); -$footnote = $textrun->createFootnote(); +$footnote = $textrun->addFootnote(); $footnote->addText('Just like a textrun, a footnote can contain native texts. '); $footnote->addText('No break is placed after adding an element. ', 'BoldText'); $footnote->addText('All elements are placed inside a paragraph. ', 'ColoredText'); @@ -34,7 +34,7 @@ $footnote->addObject('resources/_sheet.xls'); $footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.'); -$footnote = $section->createFootnote(); +$footnote = $section->addFootnote(); $footnote->addText('The reference for this is wrapped in its own line'); // Save file diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index eeef6058..4b184cfd 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -11,7 +11,7 @@ $phpWord->setDefaultParagraphStyle(array( )); // Sample -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Below are the samples on how to control your paragraph ' . 'pagination. See "Line and Page Break" tab on paragraph properties ' . diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 0c9fbeb5..d841092c 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -4,7 +4,7 @@ include_once 'Sample_Header.php'; // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); // 1. Basic table diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 6e8b26a0..d4ea2c4a 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -4,7 +4,7 @@ include_once 'Sample_Header.php'; // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); //1.Use EastAisa FontStyle $section->addText('中文楷体样式测试',array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 19139ab2..a30358f2 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -6,10 +6,10 @@ echo date('H:i:s') , " Create new PhpWord object" , \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add first page header -$header = $section->createHeader(); +$header = $section->addHeader(); $header->firstPage(); $table = $header->addTable(); $table->addRow(); @@ -23,11 +23,11 @@ $table->addCell(4500)->addImage( ); // Add header for all other pages -$subsequent = $section->createHeader(); +$subsequent = $section->addHeader(); $subsequent->addText("Subsequent pages in Section 1 will Have this!"); // Add footer -$footer = $section->createFooter(); +$footer = $section->addFooter(); $footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', array('align' => 'center')); $footer->addLink('http://google.com', 'Direct Google'); @@ -50,9 +50,9 @@ $section->addTextBreak(); $section->addText('Some text...'); // New portrait section -$section2 = $phpWord->createSection(); +$section2 = $phpWord->addSection(); -$sec2Header = $section2->createHeader(); +$sec2Header = $section2->addHeader(); $sec2Header->addText("All pages in Section 2 will Have this!"); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index cf467464..405f653b 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -6,7 +6,7 @@ echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Local image without any styles:'); $section->addImage('resources/_mars.jpg'); $section->addTextBreak(2); diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 45cb73ab..a7dc48ff 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -6,7 +6,7 @@ echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add listitem elements $section->addListItem('List Item 1', 0); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index 06628de5..a2e4f9e1 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -6,7 +6,7 @@ echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add hyperlink elements $section->addLink('http://www.google.com', 'Best search engine', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index 1a7f557a..ec2dbce4 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -6,7 +6,7 @@ echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 27982921..951632af 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -6,7 +6,7 @@ echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Define the TOC font style $fontStyle = array('spaceAfter'=>60, 'size'=>12); diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index ff299c97..96fe5c99 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -7,8 +7,8 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); -$header = $section->createHeader(); +$section = $phpWord->addSection(); +$header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); $section->addText('The header reference to the current section includes a watermark image.'); diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index 9433222c..b594bebd 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -12,7 +12,7 @@ $phpWord->addFontStyle('fontStyle', array('size' => 9)); $phpWord->addParagraphStyle('paragraphStyle', array('spacing' => 480)); $fontStyle = array('size' => 24); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Text break with no style:'); $section->addTextBreak(); $section->addText('Text break with defined font style:'); diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index 46a232f7..ed6ec320 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -4,7 +4,7 @@ include_once 'Sample_Header.php'; // New Word document echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText("This is some text highlighted using fgColor (limited to 15 colors) ", array("fgColor" => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW)); $section->addText("This one uses bgColor and is using hex value (0xfbbb10)", array("bgColor" => "fbbb10")); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index c02ac2ba..6f3575cd 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -4,7 +4,7 @@ include_once 'Sample_Header.php'; // New Word document echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText("By default, when you insert an image, it adds a textbreak after its content."); $section->addText("If we want a simple border around an image, we wrap the image inside a table->row->cell"); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 505d3518..3c2b64e5 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -5,7 +5,7 @@ include_once 'Sample_Header.php'; echo date('H:i:s'), " Create new PhpWord object", \EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Check box in section'); $section->addCheckBox('chkBox1', 'Checkbox 1'); $section->addText('Check box in table cell'); diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 894d7df7..89ee8d94 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -23,6 +23,7 @@ class PhpWord const DEFAULT_FONT_COLOR = '000000'; // HEX const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs const DEFAULT_FONT_NAME = 'Arial'; + /** * Default font size, in points. * @@ -34,7 +35,7 @@ class PhpWord /** * Document properties object * - * @var \PhpOffice\PhpWord\DocumentProperties + * @var DocumentProperties */ private $_documentProperties; @@ -54,7 +55,7 @@ class PhpWord /** * Collection of sections * - * @var \PhpOffice\PhpWord\Section[] + * @var Section[] */ private $_sections = array(); @@ -71,7 +72,7 @@ class PhpWord /** * Get document properties object * - * @return \PhpOffice\PhpWord\DocumentProperties + * @return DocumentProperties */ public function getDocumentProperties() { @@ -95,9 +96,9 @@ class PhpWord * Create new section * * @param \PhpOffice\PhpWord\Container\Settings $settings - * @return \PhpOffice\PhpWord\Container\Section + * @return Section */ - public function createSection($settings = null) + public function addSection($settings = null) { $section = new Section(\count($this->_sections) + 1, $settings); $this->_sections[] = $section; @@ -227,8 +228,8 @@ class PhpWord * Load template by filename * * @param string $filename Fully qualified filename. - * @return \PhpOffice\PhpWord\Template - * @throws \PhpOffice\PhpWord\Exception\Exception + * @return Template + * @throws Exception */ public function loadTemplate($filename) { @@ -238,4 +239,16 @@ class PhpWord throw new Exception("Template file {$filename} not found."); } } + + /** + * Create new section + * + * @param \PhpOffice\PhpWord\Container\Settings $settings + * @return Section + * @deprecated 0.9.2 + */ + public function createSection($settings = null) + { + return $this->addSection($settings); + } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 36ff79e3..be84d636 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -173,7 +173,7 @@ class Word2007 extends Reader implements IReader ); $xmlDoc = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}", true)); if (is_object($xmlDoc)) { - $section = $word->createSection(); + $section = $word->addSection(); foreach ($xmlDoc->body->children() as $elm) { $elmName = $elm->getName(); @@ -181,7 +181,7 @@ class Word2007 extends Reader implements IReader // Create new section if section setting found if ($elm->pPr->sectPr) { $section->setSettings($this->loadSectionSettings($elm->pPr)); - $section = $word->createSection(); + $section = $word->addSection(); continue; } // Has w:r? It's either text or textrun diff --git a/tests/PhpWord/Tests/Container/FooterTest.php b/tests/PhpWord/Tests/Container/FooterTest.php index 74a09a51..ba712903 100644 --- a/tests/PhpWord/Tests/Container/FooterTest.php +++ b/tests/PhpWord/Tests/Container/FooterTest.php @@ -73,7 +73,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase public function testCreateTextRun() { $oFooter = new Footer(1); - $element = $oFooter->createTextRun(); + $element = $oFooter->addTextRun(); $this->assertCount(1, $oFooter->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php index 9d479ade..dab67048 100644 --- a/tests/PhpWord/Tests/Container/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -84,7 +84,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase public function testCreateTextRun() { $oHeader = new Header(1); - $element = $oHeader->createTextRun(); + $element = $oHeader->addTextRun(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); $this->assertCount(1, $oHeader->getElements()); } diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php index 0517399c..a289df49 100644 --- a/tests/PhpWord/Tests/Container/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -86,8 +86,8 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSource); $section->addMemoryImage($imageUrl); $section->addTitle(utf8_decode('ä'), 1); - $section->createTextRun(); - $section->createFootnote(); + $section->addTextRun(); + $section->addFootnote(); $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); $section->addTOC(); diff --git a/tests/PhpWord/Tests/Element/Table/CellTest.php b/tests/PhpWord/Tests/Element/Table/CellTest.php index d16f275a..bc0a8db1 100644 --- a/tests/PhpWord/Tests/Element/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/Table/CellTest.php @@ -276,7 +276,7 @@ class CellTest extends \PHPUnit_Framework_TestCase public function testCreateTextRun() { $oCell = new Cell('section', 1); - $element = $oCell->createTextRun(); + $element = $oCell->addTextRun(); $this->assertCount(1, $oCell->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); diff --git a/tests/PhpWord/Tests/Element/TextRunTest.php b/tests/PhpWord/Tests/Element/TextRunTest.php index e71ce108..6f277e82 100644 --- a/tests/PhpWord/Tests/Element/TextRunTest.php +++ b/tests/PhpWord/Tests/Element/TextRunTest.php @@ -138,7 +138,7 @@ class TextRunTest extends \PHPUnit_Framework_TestCase public function testCreateFootnote() { $oTextRun = new TextRun(); - $element = $oTextRun->createFootnote(); + $element = $oTextRun->addFootnote(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $element); $this->assertCount(1, $oTextRun->getElements()); diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 2cf5ae62..829ddfff 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -51,8 +51,8 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase public function testCreateGetSections() { $phpWord = new PhpWord(); - $this->assertEquals(new Section(1), $phpWord->createSection()); - $phpWord->createSection(); + $this->assertEquals(new Section(1), $phpWord->addSection()); + $phpWord->addSection(); $this->assertEquals(2, \count($phpWord->getSections())); } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 47ed57f4..d26b97fe 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -103,7 +103,7 @@ class FontTest extends \PHPUnit_Framework_TestCase public function testLineHeight() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // Test style array $text = $section->addText('This is a test', array( diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 4c424a93..10a74dae 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -105,7 +105,7 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase public function testLineHeight() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // Test style array $text = $section->addText('This is a test', array(), array( diff --git a/tests/PhpWord/Tests/Writer/ODText/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/ContentTest.php index 377f07c2..4808de9e 100644 --- a/tests/PhpWord/Tests/Writer/ODText/ContentTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/ContentTest.php @@ -41,7 +41,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $phpWord->setDefaultFontName('Verdana'); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText($expected); $section->addText('Test font style', 'Font'); $section->addText('Test paragraph style', null, 'Paragraph'); @@ -54,7 +54,7 @@ class ContentTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addText('Test text run'); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 82263c0f..743907be 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -64,7 +64,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test 1', 'Font'); $section->addTextBreak(); $section->addText('Test 2', null, 'Paragraph'); @@ -76,8 +76,8 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); $writer = new ODText($phpWord); $writer->save($file); @@ -95,7 +95,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase public function testSavePhpOutput() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test'); $writer = new ODText($phpWord); $writer->save('php://output'); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 4872ef39..1abeeefa 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -52,7 +52,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); @@ -64,8 +64,8 @@ class RTFTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); $textrun->addTextBreak(); $writer = new RTF($phpWord); @@ -84,7 +84,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase public function testSavePhpOutput() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test'); $writer = new RTF($phpWord); $writer->save('php://output'); diff --git a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php index 18524f58..d9d1b3c5 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php @@ -38,7 +38,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle($rStyle, array('bold' => true)); $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test', $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); @@ -59,14 +59,14 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addParagraphStyle($pStyle, $aStyle); - $section = $phpWord->createSection('Test'); - $textrun = $section->createTextRun($pStyle); + $section = $phpWord->addSection('Test'); + $textrun = $section->addTextRun($pStyle); $textrun->addText('Test'); $textrun->addTextBreak(); - $textrun = $section->createTextRun($aStyle); + $textrun = $section->addTextRun($aStyle); $textrun->addLink('http://test.com'); $textrun->addImage($imageSrc, array('align' => 'top')); - $textrun->createFootnote(); + $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); $parent = "/w:document/w:body/w:p"; @@ -79,7 +79,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWriteLink() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font Style'; $paragraphStyleArray = array('align' => 'center'); @@ -102,8 +102,8 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWritePreserveText() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $footer = $section->createFooter(); + $section = $phpWord->addSection(); + $footer = $section->addFooter(); $fontStyleArray = array('bold' => true); $fontStyleName = 'Font'; $paragraphStyleArray = array('align' => 'right'); @@ -133,7 +133,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle($fName, $fArray); $phpWord->addParagraphStyle($pName, $pArray); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addTextBreak(); $section->addTextBreak(1, $fArray, $pArray); $section->addTextBreak(1, $fName, $pName); @@ -151,7 +151,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWriteParagraphStyleAlign() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('This is my text', null, array('align' => 'right')); @@ -168,7 +168,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase { // Create the doc $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $attributes = array( 'widowControl' => false, 'keepNext' => true, @@ -209,7 +209,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $styles['bgColor'] = 'FFFF00'; $styles['hint'] = 'eastAsia'; - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test', $styles); $doc = TestHelperDOCX::getDocument($phpWord); @@ -257,7 +257,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cStyles["borderRightColor"] = 'FF0000'; $cStyles["vMerge"] = 'restart'; - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $table = $section->addTable($tStyles); $table->setWidth = 100; $table->addRow($rHeight, $rStyles); @@ -268,7 +268,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cell->addListItem('Test'); $cell->addImage($imageSrc); $cell->addObject($objectSrc); - $textrun = $cell->createTextRun(); + $textrun = $cell->addTextRun(); $textrun->addText('Test'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -296,7 +296,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWriteCellStyleCellGridSpan() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $table = $section->addTable(); @@ -323,7 +323,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWriteImagePosition() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addImage( __DIR__ . "/../../_files/images/earth.jpg", array( @@ -350,8 +350,8 @@ class BaseTest extends \PHPUnit_Framework_TestCase $imageSrc = __DIR__ . "/../../_files/images/earth.jpg"; $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $header = $section->createHeader(); + $section = $phpWord->addSection(); + $header = $section->addHeader(); $header->addWatermark($imageSrc); $doc = TestHelperDOCX::getDocument($phpWord); @@ -366,7 +366,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); - $phpWord->createSection()->addTitle('Test', 1); + $phpWord->addSection()->addTitle('Test', 1); $doc = TestHelperDOCX::getDocument($phpWord); $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; @@ -386,7 +386,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle($rStyle, array('bold' => true)); $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addCheckbox('Check1', 'Test', $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php index 5318ac81..8cceecb3 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php @@ -33,7 +33,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase public function testWriteEndSectionPageNumbering() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $settings = $section->getSettings(); $settings->setLandscape(); $settings->setPageNumberingStart(2); @@ -56,14 +56,14 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addTitleStyle(1, array('color' => '333333', 'bold'=>true)); $phpWord->addTitleStyle(2, array('color'=>'666666')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addTOC(); $section->addPageBreak(); $section->addTitle('Title 1', 1); $section->addListItem('List Item 1', 0); $section->addListItem('List Item 2', 0); $section->addListItem('List Item 3', 0); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addTitle('Title 2', 2); $section->addObject($objectSrc); $doc = TestHelperDOCX::getDocument($phpWord); @@ -103,7 +103,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $phpWord->addFontStyle('fStyle', array('size' => '20')); $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); $fontStyle = new Font('text', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addListItem('List Item', 0, null, null, 'pStyle'); $section->addObject($objectSrc, array('align' => 'center')); $section->addTOC($fontStyle); diff --git a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php index c0f94de6..04e86832 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php @@ -32,7 +32,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $container->addText(''); $container->addPreserveText(''); $container->addTextBreak(); - $container->createTextRun(); + $container->addTextRun(); $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php index 6baba0ac..11817962 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php @@ -34,13 +34,13 @@ class FootnotesTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $phpWord->addParagraphStyle('pStyle', array('align' => 'left')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Text'); - $footnote1 = $section->createFootnote('pStyle'); + $footnote1 = $section->addFootnote('pStyle'); $footnote1->addText('Footnote'); $footnote1->addTextBreak(); $footnote1->addLink('http://google.com'); - $footnote2 = $section->createFootnote(array('align' => 'left')); + $footnote2 = $section->addFootnote(array('align' => 'left')); $footnote2->addText('Footnote'); $doc = TestHelperDOCX::getDocument($phpWord); diff --git a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php index 253f663e..c468d7a7 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php @@ -30,7 +30,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $container->addText('Test'); $container->addPreserveText(''); $container->addTextBreak(); - $container->createTextRun(); + $container->addTextRun(); $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); $container->addWatermark($imageSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index f486d18d..7b722a9c 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -68,18 +68,18 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); $section->addText('Test 2'); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); - $footnote = $textrun->createFootnote(); + $footnote = $textrun->addFootnote(); $footnote->addLink('http://test.com'); - $header = $section->createHeader(); + $header = $section->addHeader(); $header->addImage($localImage); - $footer = $section->createFooter(); + $footer = $section->addFooter(); $footer->addImage($remoteImage); $writer = new Word2007($phpWord); @@ -97,9 +97,9 @@ class Word2007Test extends \PHPUnit_Framework_TestCase public function testSaveUseDiskCaching() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test'); - $footnote = $section->createFootnote(); + $footnote = $section->addFootnote(); $footnote->addText('Test'); $writer = new Word2007($phpWord); @@ -138,7 +138,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase 'angela_merkel.tif' => '6.tif', ); $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); foreach ($images as $source => $target) { $section->addImage(__DIR__ . "/../_files/images/{$source}"); } @@ -169,7 +169,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase public function testSetGetUseDiskCaching() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $object = new Word2007($phpWord); $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); $writer = new Word2007($phpWord); From 06ba9e70930aabac16b4e1aa8ddc8e58ab92b17a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 2 Apr 2014 11:11:59 +0700 Subject: [PATCH 045/146] Make one level Element folder structure (move Cell and Row up one level) --- src/PhpWord/Element/{Table => }/Cell.php | 2 +- src/PhpWord/Element/{Table => }/Row.php | 4 ++-- src/PhpWord/Element/Table.php | 4 ++-- .../Tests/Element/{Table => }/CellTest.php | 18 +++++++++--------- .../Tests/Element/{Table => }/RowTest.php | 12 ++++++------ tests/PhpWord/Tests/Element/TableTest.php | 4 ++-- 6 files changed, 22 insertions(+), 22 deletions(-) rename src/PhpWord/Element/{Table => }/Cell.php (97%) rename src/PhpWord/Element/{Table => }/Row.php (95%) rename tests/PhpWord/Tests/Element/{Table => }/CellTest.php (93%) rename tests/PhpWord/Tests/Element/{Table => }/RowTest.php (79%) diff --git a/src/PhpWord/Element/Table/Cell.php b/src/PhpWord/Element/Cell.php similarity index 97% rename from src/PhpWord/Element/Table/Cell.php rename to src/PhpWord/Element/Cell.php index 2a15a263..25e9fb71 100755 --- a/src/PhpWord/Element/Table/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Element\Table; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Cell as CellStyle; diff --git a/src/PhpWord/Element/Table/Row.php b/src/PhpWord/Element/Row.php similarity index 95% rename from src/PhpWord/Element/Table/Row.php rename to src/PhpWord/Element/Row.php index c027d373..eefeca57 100644 --- a/src/PhpWord/Element/Table/Row.php +++ b/src/PhpWord/Element/Row.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Element\Table; +namespace PhpOffice\PhpWord\Element; /** * Table row element @@ -83,7 +83,7 @@ class Row * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table\Cell + * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index fc168349..083ad5fc 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Element\Table\Row; +use PhpOffice\PhpWord\Element\Row; /** * Table element @@ -98,7 +98,7 @@ class Table * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Table\Cell + * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) { diff --git a/tests/PhpWord/Tests/Element/Table/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php similarity index 93% rename from tests/PhpWord/Tests/Element/Table/CellTest.php rename to tests/PhpWord/Tests/Element/CellTest.php index bc0a8db1..be541935 100644 --- a/tests/PhpWord/Tests/Element/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Element\Table; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Element\Table\Cell; +use PhpOffice\PhpWord\Element\Cell; /** - * Test class for PhpOffice\PhpWord\Element\Table\Cell + * Test class for PhpOffice\PhpWord\Element\Cell * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oCell = new Cell('section', $iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $oCell); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell); $this->assertEquals($oCell->getWidth(), null); } @@ -132,7 +132,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddImageSection() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('section', 1); $element1 = $oCell->addImage($src); $element2 = $oCell->addMemoryImage($src); // @deprecated @@ -146,7 +146,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddImageHeader() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('header', 1); $element = $oCell->addImage($src); @@ -159,7 +159,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddImageFooter() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('footer', 1); $element = $oCell->addImage($src); @@ -214,7 +214,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddObjectXLS() { - $src = __DIR__ . "/../../_files/documents/sheet.xls"; + $src = __DIR__ . "/../_files/documents/sheet.xls"; $oCell = new Cell('section', 1); $element = $oCell->addObject($src); @@ -229,7 +229,7 @@ class CellTest extends \PHPUnit_Framework_TestCase */ public function testAddObjectException() { - $src = __DIR__ . "/_files/xsl/passthrough.xsl"; + $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; $oCell = new Cell('section', 1); $element = $oCell->addObject($src); } diff --git a/tests/PhpWord/Tests/Element/Table/RowTest.php b/tests/PhpWord/Tests/Element/RowTest.php similarity index 79% rename from tests/PhpWord/Tests/Element/Table/RowTest.php rename to tests/PhpWord/Tests/Element/RowTest.php index f64c0cb4..e232afa8 100644 --- a/tests/PhpWord/Tests/Element/Table/RowTest.php +++ b/tests/PhpWord/Tests/Element/RowTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Element\Table; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Element\Table\Row; +use PhpOffice\PhpWord\Element\Row; /** - * Test class for PhpOffice\PhpWord\Element\Table\Row + * Test class for PhpOffice\PhpWord\Element\Row * - * @coversDefaultClass \PhpOffice\PhpWord\Element\Table\Row + * @coversDefaultClass \PhpOffice\PhpWord\Element\Row * @runTestsInSeparateProcesses */ class RowTest extends \PHPUnit_Framework_TestCase @@ -27,7 +27,7 @@ class RowTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oRow = new Row('section', $iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Row', $oRow); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); $this->assertEquals($oRow->getHeight(), null); $this->assertInternalType('array', $oRow->getCells()); $this->assertCount(0, $oRow->getCells()); @@ -60,7 +60,7 @@ class RowTest extends \PHPUnit_Framework_TestCase $oRow = new Row('section', 1); $element = $oRow->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); $this->assertCount(1, $oRow->getCells()); } } diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php index 1b337fd6..0d3a74b9 100644 --- a/tests/PhpWord/Tests/Element/TableTest.php +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -75,7 +75,7 @@ class TableTest extends \PHPUnit_Framework_TestCase { $oTable = new Table('section', 1); $element = $oTable->addRow(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Row', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element); $this->assertCount(1, $oTable->getRows()); } @@ -87,6 +87,6 @@ class TableTest extends \PHPUnit_Framework_TestCase $oTable = new Table('section', 1); $oTable->addRow(); $element = $oTable->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table\\Cell', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); } } From 51a8628209016a7e8e6fd2550a2bee2ce238e590 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 2 Apr 2014 18:57:34 +0700 Subject: [PATCH 046/146] Merge #190, reorder methods (public, protected, private), and add example to Sample_07_TemplateCloneRow --- CHANGELOG.md | 1 + samples/Sample_07_TemplateCloneRow.php | 8 +- .../resources/Sample_07_TemplateCloneRow.docx | Bin 17939 -> 22835 bytes src/PhpWord/Template.php | 370 +++++++++--------- tests/PhpWord/Tests/TemplateTest.php | 3 + 5 files changed, 194 insertions(+), 188 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c785dbf4..08ef04fb 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 - Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 - Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 +- Template: Ability to find & replace variables in headers & footers - @dgudgeon GH-190 ### Bugfixes diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index 4344fafc..72464d84 100755 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -7,6 +7,11 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); $document = $phpWord->loadTemplate('resources/Sample_07_TemplateCloneRow.docx'); +// Variables on different parts of document +$document->setValue('weekday', date('l')); // On section/content +$document->setValue('time', date('H:i')); // On footer +$document->setValue('serverName', $_SERVER['SERVER_NAME']); // On header + // Simple table $document->cloneRow('rowValue', 10); @@ -32,9 +37,6 @@ $document->setValue('rowNumber#8', '8'); $document->setValue('rowNumber#9', '9'); $document->setValue('rowNumber#10', '10'); -$document->setValue('weekday', date('l')); -$document->setValue('time', date('H:i')); - // Table with a spanned cell $document->cloneRow('userId', 3); diff --git a/samples/resources/Sample_07_TemplateCloneRow.docx b/samples/resources/Sample_07_TemplateCloneRow.docx index 25a8c418b6795873777334de254fae7081e1fa14..9ac6c2a18d8979b98e86006dafd1a3f65546bfd6 100755 GIT binary patch delta 18508 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 = tempnam(sys_get_temp_dir(), ''); - if ($this->_tempFileName === false) { + $this->tempFileName = tempnam(sys_get_temp_dir(), ''); + if ($this->tempFileName === false) { throw new Exception('Could not create temporary file with unique name in the default temporary directory.'); } // Copy the source File to the temp File - if (!copy($strFilename, $this->_tempFileName)) { - throw new Exception("Could not copy the template from {$strFilename} to {$this->_tempFileName}."); + if (!copy($strFilename, $this->tempFileName)) { + throw new Exception("Could not copy the template from {$strFilename} to {$this->tempFileName}."); } $zipClass = Settings::getZipClass(); - $this->_objZip = new $zipClass(); - $this->_objZip->open($this->_tempFileName); + $this->zipClass = new $zipClass(); + $this->zipClass->open($this->tempFileName); // Find and load headers and footers $i = 1; - while ($this->_objZip->locateName($this->getHeaderName($i)) !== false) { - $this->_headerXMLs[$i] = $this->_objZip->getFromName($this->getHeaderName($i)); + while ($this->zipClass->locateName($this->getHeaderName($i)) !== false) { + $this->headerXMLs[$i] = $this->zipClass->getFromName($this->getHeaderName($i)); $i++; } $i = 1; - while ($this->_objZip->locateName($this->getFooterName($i)) !== false) { - $this->_footerXMLs[$i] = $this->_objZip->getFromName($this->getFooterName($i)); + while ($this->zipClass->locateName($this->getFooterName($i)) !== false) { + $this->footerXMLs[$i] = $this->zipClass->getFromName($this->getFooterName($i)); $i++; } - $this->_documentXML = $this->_objZip->getFromName('word/document.xml'); - } - - /** - * Get the name of the footer file for $index - * @param integer $index - * @return string - */ - private function getFooterName($index) - { - return sprintf('word/footer%d.xml', $index); - } - - /** - * Get the name of the header file for $index - * @param integer $index - * @return string - */ - private function getHeaderName($index) - { - return sprintf('word/header%d.xml', $index); + $this->documentXML = $this->zipClass->getFromName('word/document.xml'); } /** @@ -117,7 +97,7 @@ class Template * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { @@ -130,7 +110,7 @@ class Template } $xmlDOMDocument = new \DOMDocument(); - if ($xmlDOMDocument->loadXML($this->_documentXML) === false) { + if ($xmlDOMDocument->loadXML($this->documentXML) === false) { throw new Exception('Could not load XML from the given template.'); } @@ -139,7 +119,143 @@ class Template throw new Exception('Could not transform the given XML document.'); } - $this->_documentXML = $xmlTransformed; + $this->documentXML = $xmlTransformed; + } + + /** + * Set a Template value + * + * @param mixed $search + * @param mixed $replace + * @param integer $limit + */ + public function setValue($search, $replace, $limit = -1) + { + foreach ($this->headerXMLs as $index => $headerXML) { + $this->headerXMLs[$index] = $this->setValueForPart($this->headerXMLs[$index], $search, $replace, $limit); + } + + $this->documentXML = $this->setValueForPart($this->documentXML, $search, $replace, $limit); + + foreach ($this->footerXMLs as $index => $headerXML) { + $this->footerXMLs[$index] = $this->setValueForPart($this->footerXMLs[$index], $search, $replace, $limit); + } + } + + /** + * Returns array of all variables in template + * @return string[] + */ + public function getVariables() + { + $variables = $this->getVariablesForPart($this->documentXML); + + foreach ($this->headerXMLs as $headerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); + } + + foreach ($this->footerXMLs as $footerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); + } + + return array_unique($variables); + } + + /** + * Clone a table row in a template document + * + * @param string $search + * @param int $numberOfClones + * @throws Exception + */ + public function cloneRow($search, $numberOfClones) + { + if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { + $search = '${' . $search . '}'; + } + + $tagPos = strpos($this->documentXML, $search); + if (!$tagPos) { + throw new Exception("Can not clone row, template variable not found or variable contains markup."); + } + + $rowStart = $this->findRowStart($tagPos); + $rowEnd = $this->findRowEnd($tagPos); + $xmlRow = $this->getSlice($rowStart, $rowEnd); + + // Check if there's a cell spanning multiple rows. + if (preg_match('##', $xmlRow)) { + $extraRowStart = $rowEnd; + $extraRowEnd = $rowEnd; + while (true) { + $extraRowStart = $this->findRowStart($extraRowEnd + 1); + $extraRowEnd = $this->findRowEnd($extraRowEnd + 1); + + // If extraRowEnd is lower then 7, there was no next row found. + if ($extraRowEnd < 7) { + break; + } + + // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. + $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); + if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { + break; + } + // This row was a spanned row, update $rowEnd and search for the next row. + $rowEnd = $extraRowEnd; + } + $xmlRow = $this->getSlice($rowStart, $rowEnd); + } + + $result = $this->getSlice(0, $rowStart); + for ($i = 1; $i <= $numberOfClones; $i++) { + $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); + } + $result .= $this->getSlice($rowEnd); + + $this->documentXML = $result; + } + + /** + * Save XML to temporary file + * + * @return string + * @throws Exception + */ + public function save() + { + foreach ($this->headerXMLs as $index => $headerXML) { + $this->zipClass->addFromString($this->getHeaderName($index), $this->headerXMLs[$index]); + } + + $this->zipClass->addFromString('word/document.xml', $this->documentXML); + + foreach ($this->footerXMLs as $index => $headerXML) { + $this->zipClass->addFromString($this->getFooterName($index), $this->footerXMLs[$index]); + } + + // Close zip file + if ($this->zipClass->close() === false) { + throw new Exception('Could not close zip file.'); + } + + return $this->tempFileName; + } + + /** + * Save XML to defined name + * + * @param string $strFilename + */ + public function saveAs($strFilename) + { + $tempFilename = $this->save(); + + if (\file_exists($strFilename)) { + unlink($strFilename); + } + + rename($tempFilename, $strFilename); } /** @@ -181,26 +297,6 @@ class Template return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); } - /** - * Set a Template value - * - * @param mixed $search - * @param mixed $replace - * @param integer $limit - */ - public function setValue($search, $replace, $limit = -1) - { - foreach ($this->_headerXMLs as $index => $headerXML) { - $this->_headerXMLs[$index] = $this->setValueForPart($this->_headerXMLs[$index], $search, $replace, $limit); - } - - $this->_documentXML = $this->setValueForPart($this->_documentXML, $search, $replace, $limit); - - foreach ($this->_footerXMLs as $index => $headerXML) { - $this->_footerXMLs[$index] = $this->setValueForPart($this->_footerXMLs[$index], $search, $replace, $limit); - } - } - /** * Find all variables in $documentPartXML * @param string $documentPartXML @@ -214,22 +310,23 @@ class Template } /** - * Returns array of all variables in template - * @return string[] + * Get the name of the footer file for $index + * @param integer $index + * @return string */ - public function getVariables() + private function getFooterName($index) { - $variables = $this->getVariablesForPart($this->_documentXML); + return sprintf('word/footer%d.xml', $index); + } - foreach ($this->_headerXMLs as $headerXML) { - $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); - } - - foreach ($this->_footerXMLs as $footerXML) { - $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); - } - - return array_unique($variables); + /** + * Get the name of the header file for $index + * @param integer $index + * @return string + */ + private function getHeaderName($index) + { + return sprintf('word/header%d.xml', $index); } /** @@ -237,13 +334,13 @@ class Template * * @param int $offset * @return int - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws Exception */ - private function _findRowStart($offset) + private function findRowStart($offset) { - $rowStart = strrpos($this->_documentXML, "_documentXML) - $offset) * -1)); + $rowStart = strrpos($this->documentXML, "documentXML) - $offset) * -1)); if (!$rowStart) { - $rowStart = strrpos($this->_documentXML, "", ((strlen($this->_documentXML) - $offset) * -1)); + $rowStart = strrpos($this->documentXML, "", ((strlen($this->documentXML) - $offset) * -1)); } if (!$rowStart) { throw new Exception("Can not find the start position of the row to clone."); @@ -257,9 +354,9 @@ class Template * @param int $offset * @return int */ - private function _findRowEnd($offset) + private function findRowEnd($offset) { - $rowEnd = strpos($this->_documentXML, "", $offset) + 7; + $rowEnd = strpos($this->documentXML, "", $offset) + 7; return $rowEnd; } @@ -270,108 +367,11 @@ class Template * @param int $endPosition * @return string */ - private function _getSlice($startPosition, $endPosition = 0) + private function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { - $endPosition = strlen($this->_documentXML); + $endPosition = strlen($this->documentXML); } - return substr($this->_documentXML, $startPosition, ($endPosition - $startPosition)); - } - - /** - * Clone a table row in a template document - * - * @param string $search - * @param int $numberOfClones - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function cloneRow($search, $numberOfClones) - { - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { - $search = '${' . $search . '}'; - } - - $tagPos = strpos($this->_documentXML, $search); - if (!$tagPos) { - throw new Exception("Can not clone row, template variable not found or variable contains markup."); - } - - $rowStart = $this->_findRowStart($tagPos); - $rowEnd = $this->_findRowEnd($tagPos); - $xmlRow = $this->_getSlice($rowStart, $rowEnd); - - // Check if there's a cell spanning multiple rows. - if (preg_match('##', $xmlRow)) { - $extraRowStart = $rowEnd; - $extraRowEnd = $rowEnd; - while (true) { - $extraRowStart = $this->_findRowStart($extraRowEnd + 1); - $extraRowEnd = $this->_findRowEnd($extraRowEnd + 1); - - // If extraRowEnd is lower then 7, there was no next row found. - if ($extraRowEnd < 7) { - break; - } - - // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. - $tmpXmlRow = $this->_getSlice($extraRowStart, $extraRowEnd); - if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { - break; - } - // This row was a spanned row, update $rowEnd and search for the next row. - $rowEnd = $extraRowEnd; - } - $xmlRow = $this->_getSlice($rowStart, $rowEnd); - } - - $result = $this->_getSlice(0, $rowStart); - for ($i = 1; $i <= $numberOfClones; $i++) { - $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); - } - $result .= $this->_getSlice($rowEnd); - - $this->_documentXML = $result; - } - - /** - * Save XML to temporary file - * - * @return string - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function save() - { - foreach ($this->_headerXMLs as $index => $headerXML) { - $this->_objZip->addFromString($this->getHeaderName($index), $this->_headerXMLs[$index]); - } - - $this->_objZip->addFromString('word/document.xml', $this->_documentXML); - - foreach ($this->_footerXMLs as $index => $headerXML) { - $this->_objZip->addFromString($this->getFooterName($index), $this->_footerXMLs[$index]); - } - - // Close zip file - if ($this->_objZip->close() === false) { - throw new Exception('Could not close zip file.'); - } - - return $this->_tempFileName; - } - - /** - * Save XML to defined name - * - * @param string $strFilename - */ - public function saveAs($strFilename) - { - $tempFilename = $this->save(); - - if (\file_exists($strFilename)) { - unlink($strFilename); - } - - rename($tempFilename, $strFilename); + return substr($this->documentXML, $startPosition, ($endPosition - $startPosition)); } } diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index 848d7736..13ed7646 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -157,6 +157,9 @@ final class TemplateTest extends \PHPUnit_Framework_TestCase $this->assertTrue($docFound); } + /** + * Replace variables in header and footer + */ public function testVariablesCanBeReplacedInHeaderAndFooter() { $template = __DIR__ . "/_files/templates/header-footer.docx"; From 04e6dbc86a39c8df00e03a512e7d0863806efcb2 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 06:54:45 +0700 Subject: [PATCH 047/146] Remove some duplication on Word2007 writers --- src/PhpWord/Writer/Word2007/Base.php | 442 +++++++----------- src/PhpWord/Writer/Word2007/Document.php | 145 ++---- src/PhpWord/Writer/Word2007/DocumentRels.php | 73 +-- src/PhpWord/Writer/Word2007/Footer.php | 33 +- src/PhpWord/Writer/Word2007/Footnotes.php | 20 +- src/PhpWord/Writer/Word2007/FootnotesRels.php | 6 +- src/PhpWord/Writer/Word2007/Header.php | 37 +- 7 files changed, 247 insertions(+), 509 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index d5c0160a..db8bd851 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -9,7 +9,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\Link; @@ -75,27 +77,10 @@ class Base extends WriterPart */ protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) { - $elements = $textrun->getElements(); $styleParagraph = $textrun->getParagraphStyle(); $xmlWriter->startElement('w:p'); $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element, true); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element, true); - } elseif ($element instanceof TextBreak) { - $xmlWriter->writeElement('w:br'); - } elseif ($element instanceof Image) { - $this->writeImage($xmlWriter, $element, true); - } elseif ($element instanceof Object) { - $this->writeObject($xmlWriter, $element, true); - } elseif ($element instanceof Footnote) { - $this->writeFootnote($xmlWriter, $element, true); - } - } - } + $this->writeContainerElements($xmlWriter, $textrun); $xmlWriter->endElement(); // w:p } @@ -254,28 +239,31 @@ class Base extends WriterPart * @param XMLWriter $xmlWriter * @param TextBreak $element */ - protected function writeTextBreak($xmlWriter, TextBreak $element = null) + protected function writeTextBreak(XMLWriter $xmlWriter, TextBreak $element = null, $withoutP = false) { - $hasStyle = false; - $styleFont = null; - $styleParagraph = null; - if (!is_null($element)) { - $styleFont = $element->getFontStyle(); - $styleParagraph = $element->getParagraphStyle(); - $hasStyle = !is_null($styleFont) || !is_null($styleParagraph); - } - if ($hasStyle) { - $xmlWriter->startElement('w:p'); - $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); - if (!is_null($styleFont)) { - $xmlWriter->startElement('w:pPr'); - $this->writeInlineFontStyle($xmlWriter, $styleFont); - $xmlWriter->endElement(); // w:pPr + if (!$withoutP) { + $hasStyle = false; + $styleFont = null; + $styleParagraph = null; + if (!is_null($element)) { + $styleFont = $element->getFontStyle(); + $styleParagraph = $element->getParagraphStyle(); + $hasStyle = !is_null($styleFont) || !is_null($styleParagraph); + } + if ($hasStyle) { + $xmlWriter->startElement('w:p'); + $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + if (!is_null($styleFont)) { + $xmlWriter->startElement('w:pPr'); + $this->writeInlineFontStyle($xmlWriter, $styleFont); + $xmlWriter->endElement(); // w:pPr + } + $xmlWriter->endElement(); // w:p + } else { + $xmlWriter->writeElement('w:p'); } - $xmlWriter->endElement(); // w:p } else { - // Null element. No paragraph nor font style - $xmlWriter->writeElement('w:p', null); + $xmlWriter->writeElement('w:br'); } } @@ -316,16 +304,16 @@ class Base extends WriterPart */ protected function writeTable(XMLWriter $xmlWriter, Table $table) { - $_rows = $table->getRows(); - $_cRows = count($_rows); + $rows = $table->getRows(); + $cRows = count($rows); - if ($_cRows > 0) { + if ($cRows > 0) { $xmlWriter->startElement('w:tbl'); // Table grid $cellWidths = array(); - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; + for ($i = 0; $i < $cRows; $i++) { + $row = $rows[$i]; $cells = $row->getCells(); if (count($cells) <= count($cellWidths)) { continue; @@ -368,8 +356,8 @@ class Base extends WriterPart } // Table rows - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; + for ($i = 0; $i < $cRows; $i++) { + $row = $rows[$i]; $height = $row->getHeight(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); @@ -377,7 +365,6 @@ class Base extends WriterPart $exactHeight = $rowStyle->getExactHeight(); $xmlWriter->startElement('w:tr'); - if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { $xmlWriter->startElement('w:trPr'); if (!is_null($height)) { @@ -398,55 +385,23 @@ class Base extends WriterPart } $xmlWriter->endElement(); } - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('w:tc'); - $cellStyle = $cell->getStyle(); $width = $cell->getWidth(); - + $xmlWriter->startElement('w:tc'); $xmlWriter->startElement('w:tcPr'); $xmlWriter->startElement('w:tcW'); $xmlWriter->writeAttribute('w:w', $width); $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - + $xmlWriter->endElement(); // w:tcW if ($cellStyle instanceof Cell) { $this->writeCellStyle($xmlWriter, $cellStyle); } - - $xmlWriter->endElement(); - - $_elements = $cell->getElements(); - if (count($_elements) > 0) { - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->writeListItem($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->writeObject($xmlWriter, $element); - } elseif ($element instanceof CheckBox) { - $this->writeCheckBox($xmlWriter, $element); - } - } - } else { - $this->writeTextBreak($xmlWriter); - } - - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:tcPr + $this->writeContainerElements($xmlWriter, $cell); + $xmlWriter->endElement(); // w:tc } - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:tr } $xmlWriter->endElement(); } @@ -953,98 +908,35 @@ class Base extends WriterPart { $bgColor = $style->getBgColor(); $brdCol = $style->getBorderColor(); - $brdSz = $style->getBorderSize(); - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $bInsH = (!is_null($brdSz[4])) ? true : false; - $bInsV = (!is_null($brdSz[5])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom || $bInsH || $bInsV) ? true : false; - $cellMargin = $style->getCellMargin(); - $mTop = (!is_null($cellMargin[0])) ? true : false; - $mLeft = (!is_null($cellMargin[1])) ? true : false; - $mRight = (!is_null($cellMargin[2])) ? true : false; - $mBottom = (!is_null($cellMargin[3])) ? true : false; - $margins = ($mTop || $mLeft || $mRight || $mBottom) ? true : false; - if ($margins || $borders) { - $xmlWriter->startElement('w:tblPr'); - if ($margins) { - $xmlWriter->startElement('w:tblCellMar'); - if ($mTop) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:w', $cellMargin[0]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:w', $cellMargin[1]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:w', $cellMargin[2]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:w', $cellMargin[3]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); + // If any of the borders/margins is set, process them + $hasBorders = false; + for ($i = 0; $i < 6; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + break; } - if ($borders) { + } + $hasMargins = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($cellMargin[$i])) { + $hasMargins = true; + break; + } + } + if ($hasMargins || $hasBorders) { + $xmlWriter->startElement('w:tblPr'); + if ($hasMargins) { + $xmlWriter->startElement('w:tblCellMar'); + $this->writeMarginBorder($xmlWriter, $cellMargin); + $xmlWriter->endElement(); // w:tblCellMar + } + if ($hasBorders) { $xmlWriter->startElement('w:tblBorders'); - if ($bTop) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); - } - if ($bLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); - } - if ($bRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - if ($bBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - if ($bInsH) { - $xmlWriter->startElement('w:insideH'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[4]); - $xmlWriter->writeAttribute('w:color', $brdCol[4]); - $xmlWriter->endElement(); - } - if ($bInsV) { - $xmlWriter->startElement('w:insideV'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[5]); - $xmlWriter->writeAttribute('w:color', $brdCol[5]); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); + $this->writeMarginBorder($xmlWriter, $brdSz, $brdCol); + $xmlWriter->endElement(); // w:tblBorders } $xmlWriter->endElement(); // w:tblPr } @@ -1077,61 +969,37 @@ class Base extends WriterPart */ protected function writeRowStyle(XMLWriter $xmlWriter, $type, TableStyle $style) { - $brdSz = $style->getBorderSize(); - $brdCol = $style->getBorderColor(); $bgColor = $style->getBgColor(); - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $xmlWriter->startElement('w:tblStylePr'); $xmlWriter->writeAttribute('w:type', $type); - $xmlWriter->startElement('w:tcPr'); if (!is_null($bgColor)) { $xmlWriter->startElement('w:shd'); $xmlWriter->writeAttribute('w:val', 'clear'); $xmlWriter->writeAttribute('w:color', 'auto'); $xmlWriter->writeAttribute('w:fill', $bgColor); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:shd } - $xmlWriter->startElement('w:tcBorders'); - if ($bTop) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); + // Borders + $brdSz = $style->getBorderSize(); + $brdCol = $style->getBorderColor(); + $hasBorders = false; + for ($i = 0; $i < 6; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + break; + } } - if ($bLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); + if ($hasBorders) { + $xmlWriter->startElement('w:tcBorders'); + $this->writeMarginBorder($xmlWriter, $brdSz, $brdCol); + $xmlWriter->endElement(); // w:tcBorders } - if ($bRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - if ($bBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:tcPr + $xmlWriter->endElement(); // w:tblStylePr } /** @@ -1147,14 +1015,15 @@ class Base extends WriterPart $textDir = $style->getTextDirection(); $brdSz = $style->getBorderSize(); $brdCol = $style->getBorderColor(); + $hasBorders = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + break; + } + } - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom) ? true : false; - - $styles = (!is_null($bgColor) || !is_null($valign) || !is_null($textDir) || $borders) ? true : false; + $styles = (!is_null($bgColor) || !is_null($valign) || !is_null($textDir) || $hasBorders) ? true : false; if ($styles) { if (!is_null($textDir)) { @@ -1177,54 +1046,11 @@ class Base extends WriterPart $xmlWriter->endElement(); } - if ($borders) { - $_defaultColor = $style->getDefaultBorderColor(); + if ($hasBorders) { + $defaultColor = $style->getDefaultBorderColor(); $xmlWriter->startElement('w:tcBorders'); - if ($bTop) { - if (is_null($brdCol[0])) { - $brdCol[0] = $_defaultColor; - } - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); - } - - if ($bLeft) { - if (is_null($brdCol[1])) { - $brdCol[1] = $_defaultColor; - } - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); - } - - if ($bRight) { - if (is_null($brdCol[2])) { - $brdCol[2] = $_defaultColor; - } - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - - if ($bBottom) { - if (is_null($brdCol[3])) { - $brdCol[3] = $_defaultColor; - } - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - + $this->writeMarginBorder($xmlWriter, $brdSz, $brdCol, array('defaultColor' => $defaultColor)); $xmlWriter->endElement(); } } @@ -1337,4 +1163,94 @@ class Base extends WriterPart } } } + + /** + * Write container elements + * + * @param XMLWriter $xmlWriter + * @param Container $container + * @param Container $textBreak Add text break when no element found + */ + protected function writeContainerElements(XMLWriter $xmlWriter, Container $container) + { + $allowedElements = array( + 'Section' => array('Text', 'TextRun', 'Link', 'Title', 'TextBreak', 'ListItem', 'Table', 'Image', 'Object', 'CheckBox', 'Footnote', 'TOC'), + 'Header' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'CheckBox'), + 'Footer' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'CheckBox'), + 'Cell' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'Object', 'CheckBox', 'Footnote'), + 'TextRun' => array('Text', 'Link', 'TextBreak', 'Image', 'Object', 'Footnote'), + 'Footnote' => array('Text', 'Link', 'TextBreak', 'Image', 'Object'), + ); + $containerName = get_class($container); + $containerName = substr($containerName, strrpos($containerName, '\\') + 1); + if (array_key_exists($containerName, $allowedElements)) { + $containerElements = $allowedElements[$containerName]; + } else { + throw new Exception('Invalid container.'); + } + + $elements = $container->getElements(); + if (count($elements) > 0) { + foreach ($elements as $element) { + $elmName = get_class($element); + $elmName = substr($elmName, strrpos($elmName, '\\') + 1); + if (in_array($elmName, $containerElements)) { + $method = "write{$elmName}"; + // Image on Header could be watermark + if ($containerName == 'Header' && $elmName == 'Image') { + if ($element->getIsWatermark()) { + $method = "writeWatermark"; + } + } + if (in_array($containerName, array('TextRun', 'Footnote'))) { + $this->$method($xmlWriter, $element, true); + } else { + $this->$method($xmlWriter, $element); + } + } + } + } else { + if ($containerName == 'Cell') { + $this->writeTextBreak($xmlWriter); + } + } + } + + /** + * Write margin or border + * + * @param XMLWriter $xmlWriter + * @param boolean $isBorder + * @param array $sizes + * @param array $colors + */ + protected function writeMarginBorder(XMLWriter $xmlWriter, $sizes, $colors = array(), $attributes = array()) + { + $sides = array('top', 'left', 'right', 'bottom', 'insideH', 'insideV'); + $sizeCount = count($sizes) - 1; + for ($i = 0; $i < $sizeCount; $i++) { + if (!is_null($sizes[$i])) { + $xmlWriter->startElement('w:' . $sides[$i]); + if (!empty($colors)) { + if (is_null($colors[$i]) && !empty($attributes)) { + if (array_key_exists('defaultColor', $attributes)) + $colors[$i] = $attributes['defaultColor']; + + } + $xmlWriter->writeAttribute('w:val', 'single'); + $xmlWriter->writeAttribute('w:sz', $sizes[$i]); + $xmlWriter->writeAttribute('w:color', $colors[$i]); + if (!empty($attributes)) { + if (array_key_exists('space', $attributes)) { + $xmlWriter->writeAttribute('w:space', '24'); + } + } + } else { + $xmlWriter->writeAttribute('w:w', $sizes[$i]); + $xmlWriter->writeAttribute('w:type', 'dxa'); + } + $xmlWriter->endElement(); + } + } + } } diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index b6e63628..60837794 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -12,18 +12,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TOC; use PhpOffice\PhpWord\Container\Section; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\Title; -use PhpOffice\PhpWord\Element\TextBreak; use PhpOffice\PhpWord\Element\PageBreak; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Object; -use PhpOffice\PhpWord\Element\Footnote; -use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -61,44 +50,15 @@ class Document extends Base $xmlWriter->startElement('w:body'); - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); $pSection = 0; if ($countSections > 0) { - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element); - } elseif ($element instanceof Title) { - $this->writeTitle($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof PageBreak) { - $this->writePageBreak($xmlWriter); - } elseif ($element instanceof ListItem) { - $this->writeListItem($xmlWriter, $element); - } elseif ($element instanceof Table) { - $this->writeTable($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->writeObject($xmlWriter, $element); - } elseif ($element instanceof TOC) { - $this->writeTOC($xmlWriter); - } elseif ($element instanceof Footnote) { - $this->writeFootnote($xmlWriter, $element); - } elseif ($element instanceof CheckBox) { - $this->writeCheckBox($xmlWriter, $element); - } - } + $this->writeContainerElements($xmlWriter, $section); if ($pSection == $countSections) { $this->writeEndSection($xmlWriter, $section); @@ -139,8 +99,8 @@ class Document extends Base private function writeEndSection(XMLWriter $xmlWriter, Section $section) { $settings = $section->getSettings(); - $_headers = $section->getHeaders(); - $_footer = $section->getFooter(); + $headers = $section->getHeaders(); + $footer = $section->getFooter(); $pgSzW = $settings->getPageSizeW(); $pgSzH = $settings->getPageSizeH(); $orientation = $settings->getOrientation(); @@ -161,43 +121,45 @@ class Document extends Base $xmlWriter->startElement('w:sectPr'); - foreach ($_headers as &$_header) { - $rId = $_header->getRelationId(); - $xmlWriter->startElement('w:headerReference'); - $xmlWriter->writeAttribute('w:type', $_header->getType()); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->endElement(); - } - - if ($section->hasDifferentFirstPage()) { - $xmlWriter->startElement('w:titlePg'); - $xmlWriter->endElement(); - } - + // Section break if (!is_null($breakType)) { $xmlWriter->startElement('w:type'); $xmlWriter->writeAttribute('w:val', $breakType); $xmlWriter->endElement(); } - if (!is_null($_footer)) { - $rId = $_footer->getRelationId(); + // Header reference + foreach ($headers as &$header) { + $rId = $header->getRelationId(); + $xmlWriter->startElement('w:headerReference'); + $xmlWriter->writeAttribute('w:type', $header->getType()); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->endElement(); + } + if ($section->hasDifferentFirstPage()) { + $xmlWriter->startElement('w:titlePg'); + $xmlWriter->endElement(); + } + + // Footer reference + if (!is_null($footer)) { + $rId = $footer->getRelationId(); $xmlWriter->startElement('w:footerReference'); $xmlWriter->writeAttribute('w:type', 'default'); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->endElement(); } + // Page size & orientation $xmlWriter->startElement('w:pgSz'); $xmlWriter->writeAttribute('w:w', $pgSzW); $xmlWriter->writeAttribute('w:h', $pgSzH); - if (!is_null($orientation) && strtolower($orientation) != 'portrait') { $xmlWriter->writeAttribute('w:orient', $orientation); } + $xmlWriter->endElement(); // w:pgSz - $xmlWriter->endElement(); - + // Margins $xmlWriter->startElement('w:pgMar'); $xmlWriter->writeAttribute('w:top', $marginTop); $xmlWriter->writeAttribute('w:right', $marginRight); @@ -208,48 +170,19 @@ class Document extends Base $xmlWriter->writeAttribute('w:gutter', '0'); $xmlWriter->endElement(); - - if (!is_null($borders[0]) || !is_null($borders[1]) || !is_null($borders[2]) || !is_null($borders[3])) { + // Borders + $hasBorders = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($borders[$i])) { + $hasBorders = true; + break; + } + } + if ($hasBorders) { $borderColor = $settings->getBorderColor(); - $xmlWriter->startElement('w:pgBorders'); $xmlWriter->writeAttribute('w:offsetFrom', 'page'); - - if (!is_null($borders[0])) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[0]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[0]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[1])) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[1]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[1]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[2])) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[2]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[2]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[3])) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[3]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[3]); - $xmlWriter->endElement(); - } + $this->writeMarginBorder($xmlWriter, $borders, $borderColor, array('space' => '24')); $xmlWriter->endElement(); } @@ -260,12 +193,12 @@ class Document extends Base $xmlWriter->endElement(); } + // Columns $xmlWriter->startElement('w:cols'); $xmlWriter->writeAttribute('w:num', $colsNum); $xmlWriter->writeAttribute('w:space', $colsSpace); $xmlWriter->endElement(); - $xmlWriter->endElement(); } @@ -274,7 +207,7 @@ class Document extends Base * * @param XMLWriter $xmlWriter */ - private function writePageBreak(XMLWriter $xmlWriter) + protected function writePageBreak(XMLWriter $xmlWriter, PageBreak $pagebreak) { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:r'); @@ -290,7 +223,7 @@ class Document extends Base * * @param XMLWriter $xmlWriter */ - private function writeTOC(XMLWriter $xmlWriter) + protected function writeTOC(XMLWriter $xmlWriter, TOC $toc) { $titles = TOC::getTitles(); $styleFont = TOC::getStyleFont(); diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index d39527a9..2129ea38 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -20,9 +20,9 @@ class DocumentRels extends Base /** * Write word/_rels/document.xml.rels * - * @param array $_relsCollection + * @param array $relsCollection */ - public function writeDocumentRels($_relsCollection) + public function writeDocumentRels($relsCollection) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -34,73 +34,42 @@ class DocumentRels extends Base $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - // Relationship word/document.xml - $this->writeRel( - $xmlWriter, - 1, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', - 'styles.xml' + // Write static files + $staticFiles = array( + 'styles' => 'styles.xml', + 'numbering' => 'numbering.xml', + 'settings' => 'settings.xml', + 'theme' => 'theme/theme1.xml', + 'webSettings' => 'webSettings.xml', + 'fontTable' => 'fontTable.xml', ); + $i = 0; + foreach ($staticFiles as $type => $file) { + $i++; + $schema = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $type; + $this->writeRel($xmlWriter, $i, $schema, $file); + } - // Relationship word/numbering.xml - $this->writeRel( - $xmlWriter, - 2, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering', - 'numbering.xml' - ); + // Write media relationship (image, oleObject, hyperlink) + $this->writeMediaRels($xmlWriter, $relsCollection); - // Relationship word/settings.xml - $this->writeRel( - $xmlWriter, - 3, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings', - 'settings.xml' - ); - - // Relationship word/settings.xml - $this->writeRel( - $xmlWriter, - 4, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', - 'theme/theme1.xml' - ); - - // Relationship word/settings.xml - $this->writeRel( - $xmlWriter, - 5, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings', - 'webSettings.xml' - ); - - // Relationship word/settings.xml - $this->writeRel( - $xmlWriter, - 6, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable', - 'fontTable.xml' - ); - - $this->writeMediaRels($xmlWriter, $_relsCollection); $xmlWriter->endElement(); // Relationships - // Return return $xmlWriter->getData(); } /** * Write header footer rels word/_rels/*.xml.rels * - * @param array $_relsCollection + * @param array $relsCollection */ - public function writeHeaderFooterRels($_relsCollection) + public function writeHeaderFooterRels($relsCollection) { $xmlWriter = $this->getXmlWriter(); $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - $this->writeMediaRels($xmlWriter, $_relsCollection); + $this->writeMediaRels($xmlWriter, $relsCollection); $xmlWriter->endElement(); return $xmlWriter->getData(); diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index cbcbcb26..d451bccd 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -10,15 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Container\Footer as FooterElement; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -50,29 +41,7 @@ class Footer extends Base $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - $_elements = $footer->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->writeListItem($xmlWriter, $element); - } elseif ($element instanceof Table) { - $this->writeTable($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->writeImage($xmlWriter, $element); - } elseif ($element instanceof CheckBox) { - $this->writeCheckBox($xmlWriter, $element); - } - } + $this->writeContainerElements($xmlWriter, $footer); $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 9ae7473a..406b1559 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -110,23 +110,9 @@ class Footnotes extends Base $xmlWriter->writeRaw(' '); $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r - // Actual footnote contents - $elements = $footnote->getElements(); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element, true); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element, true); - } elseif ($element instanceof Image) { - $this->writeImage($xmlWriter, $element, true); - } elseif ($element instanceof Object) { - $this->writeObject($xmlWriter, $element, true); - } elseif ($element instanceof TextBreak) { - $xmlWriter->writeElement('w:br'); - } - } - } + + $this->writeContainerElements($xmlWriter, $footnote); + $xmlWriter->endElement(); // w:p $xmlWriter->endElement(); // w:footnote } diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index 49ca2181..012062e1 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -20,15 +20,15 @@ class FootnotesRels extends Base /** * Write word/_rels/footnotes.xml.rels * - * @param mixed $_relsCollection + * @param mixed $relsCollection */ - public function writeFootnotesRels($_relsCollection) + public function writeFootnotesRels($relsCollection) { $xmlWriter = $this->getXmlWriter(); $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - $this->writeMediaRels($xmlWriter, $_relsCollection); + $this->writeMediaRels($xmlWriter, $relsCollection); $xmlWriter->endElement(); return $xmlWriter->getData(); diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 7bd95ed6..6b58c99f 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -10,15 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Container\Header as HeaderElement; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\TextRun; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\PreserveText; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Element\ListItem; -use PhpOffice\PhpWord\Element\Table; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\XMLWriter; /** @@ -50,33 +41,7 @@ class Header extends Base $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - $_elements = $header->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->writeLink($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->writePreserveText($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->writeListItem($xmlWriter, $element); - } elseif ($element instanceof Table) { - $this->writeTable($xmlWriter, $element); - } elseif ($element instanceof Image) { - if (!$element->getIsWatermark()) { - $this->writeImage($xmlWriter, $element); - } else { - $this->writeWatermark($xmlWriter, $element); - } - } elseif ($element instanceof CheckBox) { - $this->writeCheckBox($xmlWriter, $element); - } - } + $this->writeContainerElements($xmlWriter, $header); $xmlWriter->endElement(); From 637c9fce6f6a18989288c8b535b5341c1b85fe20 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 08:44:41 +0700 Subject: [PATCH 048/146] Create new Element abstract class --- CHANGELOG.md | 5 +- src/PhpWord/Container/Container.php | 31 ++++++++- src/PhpWord/Element/Cell.php | 15 +---- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Element.php | 42 +++++++++++++ src/PhpWord/Element/Footnote.php | 26 ++------ src/PhpWord/Element/Image.php | 17 ++--- src/PhpWord/Element/Link.php | 66 ++++++-------------- src/PhpWord/Element/ListItem.php | 33 ++++------ src/PhpWord/Element/Object.php | 48 ++++++-------- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 45 +++---------- src/PhpWord/Element/Row.php | 55 +++++++--------- src/PhpWord/Element/Table.php | 60 +++++++----------- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 13 +--- src/PhpWord/Element/Title.php | 30 ++++----- src/PhpWord/Writer/Word2007/Base.php | 18 +++--- src/PhpWord/Writer/Word2007/Footnotes.php | 2 +- tests/PhpWord/Tests/Element/FootnoteTest.php | 4 +- 21 files changed, 228 insertions(+), 290 deletions(-) create mode 100644 src/PhpWord/Element/Element.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ddd2e89..f1430f0a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - `createHeader` replaced by `addHeader` - `createFooter` replaced by `addFooter` - `createSection` replaced by `addSection` +- `Element\Footnote::getReferenceId` replaced by `Container\Container::getRelationId` +- `Element\Footnote::setReferenceId` replaced by `Container\Container::setRelationId` ### Miscellaneous @@ -40,8 +42,9 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 - Reader: Rename AbstractReader > Reader - @ivanlanin - General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187 -- Container: Create new Container abstract class - @ivanlanin GH-187 - General: Remove legacy HashTable and all related properties/methods - @ivanlanin GH-187 +- Container: Create new Container abstract class - @ivanlanin GH-187 +- Element: Create new Element abstract class - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index fd88955e..332f0c64 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -385,7 +385,7 @@ abstract class Container $footnote = new FootnoteElement($paragraphStyle); $refID = FootnoteCollection::addFootnoteElement($footnote); - $footnote->setReferenceId($refID); + $footnote->setRelationId($refID); $this->elements[] = $footnote; return $footnote; @@ -487,6 +487,33 @@ abstract class Container return $this->addFootnote($paragraphStyle); } + /** + * Set style value + * + * Used by Footnote + * + * @param mixed $styleObject Style object, could be Font, Paragraph, Cell, Image + * @param mixed $styleValue + * @param boolean $returnObject Always return object + * @todo Remove duplicate with ..\Element\Element + */ + protected function setStyle($styleObject, $styleValue = null, $returnObject = false) + { + if (!is_null($styleValue) && is_array($styleValue)) { + foreach ($styleValue as $key => $value) { + if (substr($key, 0, 1) != '_') { + $key = '_' . $key; + } + $styleObject->setStyleValue($key, $value); + } + $style = $styleObject; + } else { + $style = $returnObject ? $styleObject : $styleValue; + } + + return $style; + } + /** * Check if a method is allowed for the current container * @@ -507,7 +534,7 @@ abstract class Container 'object' => array('section', 'textrun', 'cell', 'footnote'), 'footnote' => array('section', 'textrun', 'cell'), 'preservetext' => array('header', 'footer', 'cell'), - 'relationid' => array('header', 'footer'), + 'relationid' => array('header', 'footer', 'footnote'), 'title' => array('section'), ); $validContainerInContainers = array( diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 25e9fb71..61e2fa4c 100755 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -45,20 +45,7 @@ class Cell extends Container $this->docPart = $docPart; $this->docPartId = $docPartId; $this->width = $width; - $this->cellStyle = new CellStyle(); - - if (!is_null($style)) { - if (is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->cellStyle->setStyleValue($key, $value); - } - } else { - $this->cellStyle = $style; - } - } + $this->cellStyle = $this->setStyle(new CellStyle(), $style, true); } /** diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 9a3fcc79..187bd132 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Check box element */ -class CheckBox +class CheckBox extends Element { /** * Name content diff --git a/src/PhpWord/Element/Element.php b/src/PhpWord/Element/Element.php new file mode 100644 index 00000000..b94a62c3 --- /dev/null +++ b/src/PhpWord/Element/Element.php @@ -0,0 +1,42 @@ + $value) { + if (substr($key, 0, 1) != '_') { + $key = '_' . $key; + } + $styleObject->setStyleValue($key, $value); + } + $style = $styleObject; + } else { + $style = $returnObject ? $styleObject : $styleValue; + } + + return $style; + } +} diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 3d65a256..67cd5d9a 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -24,13 +24,6 @@ class Footnote extends Container */ private $paragraphStyle; - /** - * Footnote Reference ID - * - * @var string - */ - private $referenceId; - /** * Create new instance * @@ -39,18 +32,7 @@ class Footnote extends Container public function __construct($paragraphStyle = null) { $this->container = 'footnote'; - // Set paragraph style - if (is_array($paragraphStyle)) { - $this->paragraphStyle = new Paragraph(); - foreach ($paragraphStyle as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->paragraphStyle->setStyleValue($key, $value); - } - } else { - $this->paragraphStyle = $paragraphStyle; - } + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } /** @@ -67,19 +49,21 @@ class Footnote extends Container * Get Footnote Reference ID * * @return int + * @deprecated 0.9.2 */ public function getReferenceId() { - return $this->referenceId; + return $this->getRelationId(); } /** * Set Footnote Reference ID * * @param int $refId + * @deprecated 0.9.2 */ public function setReferenceId($refId) { - $this->referenceId = $refId; + $this->setRelationId($refId); } } diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 89ee6f37..2631ec16 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -11,11 +11,12 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; +use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Image element */ -class Image +class Image extends Element { /** * Image source @@ -27,7 +28,7 @@ class Image /** * Image style * - * @var \PhpOffice\PhpWord\Style\Image + * @var ImageStyle */ private $style; @@ -131,15 +132,7 @@ class Image // Set private properties $this->source = $source; $this->isWatermark = $isWatermark; - $this->style = new \PhpOffice\PhpWord\Style\Image(); - if (!is_null($style) && is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->style->setStyleValue($key, $value); - } - } + $this->style = $this->setStyle(new ImageStyle(), $style, true); if (isset($style['wrappingStyle'])) { $this->style->setWrappingStyle($style['wrappingStyle']); } @@ -153,7 +146,7 @@ class Image /** * Get Image style * - * @return \PhpOffice\PhpWord\Style\Image + * @return ImageStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 1b6cf22a..ee1af203 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -15,42 +15,42 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Link element */ -class Link +class Link extends Element { /** * Link source * * @var string */ - private $_linkSrc; + private $source; /** * Link name * * @var string */ - private $_linkName; + private $name; /** * Link Relation ID * * @var string */ - private $_rId; + private $relationId; /** - * Link style + * Font style * * @var string|Font */ - private $_styleFont; + private $fontStyle; /** * Paragraph style * * @var string|Paragraph */ - private $_styleParagraph; + private $paragraphStyle; /** @@ -58,41 +58,15 @@ class Link * * @param string $linkSrc * @param string $linkName - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ - public function __construct($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) + public function __construct($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { - $this->_linkSrc = $linkSrc; - $this->_linkName = $linkName; - - // Set font style - if (is_array($styleFont)) { - $this->_styleFont = new Font('text'); - - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleFont->setStyleValue($key, $value); - } - } else { - $this->_styleFont = $styleFont; - } - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } + $this->source = $linkSrc; + $this->name = $linkName; + $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); return $this; } @@ -104,7 +78,7 @@ class Link */ public function getRelationId() { - return $this->_rId; + return $this->relationId; } /** @@ -114,7 +88,7 @@ class Link */ public function setRelationId($rId) { - $this->_rId = $rId; + $this->relationId = $rId; } /** @@ -124,7 +98,7 @@ class Link */ public function getLinkSrc() { - return $this->_linkSrc; + return $this->source; } /** @@ -134,7 +108,7 @@ class Link */ public function getLinkName() { - return $this->_linkName; + return $this->name; } /** @@ -144,7 +118,7 @@ class Link */ public function getFontStyle() { - return $this->_styleFont; + return $this->fontStyle; } /** @@ -154,6 +128,6 @@ class Link */ public function getParagraphStyle() { - return $this->_styleParagraph; + return $this->paragraphStyle; } } diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index e920d4b8..6cf5d1d6 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -9,31 +9,33 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; + /** * List item element */ -class ListItem +class ListItem extends Element { /** * ListItem Style * - * @var \PhpOffice\PhpWord\Style\ListItem + * @var ListItemStyle */ - private $_style; + private $style; /** * Textrun * * @var \PhpOffice\PhpWord\Element\Text */ - private $_textObject; + private $textObject; /** * ListItem Depth * * @var int */ - private $_depth; + private $depth; /** @@ -47,18 +49,9 @@ class ListItem */ public function __construct($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) { - $this->_style = new \PhpOffice\PhpWord\Style\ListItem(); - $this->_textObject = new Text($text, $styleFont, $styleParagraph); - $this->_depth = $depth; - - if (!is_null($styleList) && is_array($styleList)) { - foreach ($styleList as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } + $this->textObject = new Text($text, $styleFont, $styleParagraph); + $this->depth = $depth; + $this->style = $this->setStyle(new ListItemStyle(), $styleList, true); } /** @@ -66,7 +59,7 @@ class ListItem */ public function getStyle() { - return $this->_style; + return $this->style; } /** @@ -74,7 +67,7 @@ class ListItem */ public function getTextObject() { - return $this->_textObject; + return $this->textObject; } /** @@ -82,6 +75,6 @@ class ListItem */ public function getDepth() { - return $this->_depth; + return $this->depth; } } diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 61bf6f8e..26207787 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -9,45 +9,47 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Image as ImageStyle; + /** * Object element */ -class Object +class Object extends Element { /** * Ole-Object Src * * @var string */ - private $_src; + private $source; /** * Image Style * * @var \PhpOffice\PhpWord\Style\Image */ - private $_style; + private $style; /** * Object Relation ID * * @var int */ - private $_rId; + private $relationId; /** * Image Relation ID * * @var int */ - private $_rIdImg; + private $imageRelationId; /** * Object ID * * @var int */ - private $_objId; + private $objectId; /** @@ -58,22 +60,12 @@ class Object */ public function __construct($src, $style = null) { - $_supportedObjectTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'); + $supportedTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'); $inf = pathinfo($src); - if (\file_exists($src) && in_array($inf['extension'], $_supportedObjectTypes)) { - $this->_src = $src; - $this->_style = new \PhpOffice\PhpWord\Style\Image(); - - if (!is_null($style) && is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } - + if (\file_exists($src) && in_array($inf['extension'], $supportedTypes)) { + $this->source = $src; + $this->style = $this->setStyle(new ImageStyle(), $style, true); return $this; } else { return false; @@ -87,7 +79,7 @@ class Object */ public function getStyle() { - return $this->_style; + return $this->style; } /** @@ -97,7 +89,7 @@ class Object */ public function getSource() { - return $this->_src; + return $this->source; } /** @@ -107,7 +99,7 @@ class Object */ public function getRelationId() { - return $this->_rId; + return $this->relationId; } /** @@ -117,7 +109,7 @@ class Object */ public function setRelationId($rId) { - $this->_rId = $rId; + $this->relationId = $rId; } /** @@ -127,7 +119,7 @@ class Object */ public function getImageRelationId() { - return $this->_rIdImg; + return $this->imageRelationId; } /** @@ -137,7 +129,7 @@ class Object */ public function setImageRelationId($rId) { - $this->_rIdImg = $rId; + $this->imageRelationId = $rId; } /** @@ -147,7 +139,7 @@ class Object */ public function getObjectId() { - return $this->_objId; + return $this->objectId; } /** @@ -157,6 +149,6 @@ class Object */ public function setObjectId($objId) { - $this->_objId = $objId; + $this->objectId = $objId; } } diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index 4e49582d..c297681d 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Element; /** * Page break element */ -class PageBreak +class PageBreak extends Element { /** * Create new page break diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 453e9b84..0fe77d9a 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -15,28 +15,28 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Preserve text/field element */ -class PreserveText +class PreserveText extends Element { /** * Text content * * @var string */ - private $_text; + private $text; /** * Text style * * @var string|Font */ - private $_styleFont; + private $fontStyle; /** * Paragraph style * * @var string|Paragraph */ - private $_styleParagraph; + private $paragraphStyle; /** @@ -49,37 +49,12 @@ class PreserveText */ public function __construct($text = null, $styleFont = null, $styleParagraph = null) { - // Set font style - if (is_array($styleFont)) { - $this->_styleFont = new Font('text'); - - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleFont->setStyleValue($key, $value); - } - } else { - $this->_styleFont = $styleFont; - } - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } + $this->fontStyle = $this->setStyle(new Font('text'), $styleFont); + $this->paragraphStyle = $this->setStyle(new Paragraph(), $styleParagraph); $matches = preg_split('/({.*?})/', $text, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { - $this->_text = $matches; + $this->text = $matches; } return $this; @@ -92,7 +67,7 @@ class PreserveText */ public function getFontStyle() { - return $this->_styleFont; + return $this->fontStyle; } /** @@ -102,7 +77,7 @@ class PreserveText */ public function getParagraphStyle() { - return $this->_styleParagraph; + return $this->paragraphStyle; } /** @@ -112,6 +87,6 @@ class PreserveText */ public function getText() { - return $this->_text; + return $this->text; } } diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index eefeca57..25357062 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -9,73 +9,63 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Row as RowStyle; + /** * Table row element */ -class Row +class Row extends Element { /** * Row height * * @var int */ - private $_height = null; + private $height = null; /** * Row style * - * @var \PhpOffice\PhpWord\Style\Row + * @var RowStyle */ - private $_style; + private $style; /** * Row cells * * @var array */ - private $_cells = array(); + private $cells = array(); /** * Table holder * * @var string */ - private $_insideOf; + private $docPart; /** * Section/Header/Footer count * * @var int */ - private $_pCount; + private $docPartId; /** * Create a new table row * - * @param string $insideOf - * @param int $pCount + * @param string $docPart + * @param int $docPartId * @param int $height * @param mixed $style */ - public function __construct($insideOf, $pCount, $height = null, $style = null) + public function __construct($docPart, $docPartId, $height = null, $style = null) { - $this->_insideOf = $insideOf; - $this->_pCount = $pCount; - $this->_height = $height; - $this->_style = new \PhpOffice\PhpWord\Style\Row(); - - if (!is_null($style)) { - if (is_array($style)) { - - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } - } + $this->docPart = $docPart; + $this->docPartId = $docPartId; + $this->height = $height; + $this->style = $this->setStyle(new RowStyle(), $style, true); } /** @@ -83,12 +73,11 @@ class Row * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Cell */ public function addCell($width = null, $style = null) { - $cell = new Cell($this->_insideOf, $this->_pCount, $width, $style); - $this->_cells[] = $cell; + $cell = new Cell($this->docPart, $this->docPartId, $width, $style); + $this->cells[] = $cell; return $cell; } @@ -99,17 +88,17 @@ class Row */ public function getCells() { - return $this->_cells; + return $this->cells; } /** * Get row style * - * @return \PhpOffice\PhpWord\Style\Row + * @return RowStyle */ public function getStyle() { - return $this->_style; + return $this->style; } /** @@ -119,6 +108,6 @@ class Row */ public function getHeight() { - return $this->_height; + return $this->height; } } diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 083ad5fc..0035b897 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -10,74 +10,60 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Element\Row; - +use PhpOffice\PhpWord\Style\Table as TableStyle; /** * Table element */ -class Table +class Table extends Element { /** * Table style * - * @var \PhpOffice\PhpWord\Style\Table + * @var TableStyle */ - private $_style; + private $style; /** * Table rows * * @var array */ - private $_rows = array(); + private $rows = array(); /** * Table holder * * @var string */ - private $_insideOf = null; + private $docPart = null; /** * Table holder count * * @var array */ - private $_pCount; + private $docPartId; /** * Table width * * @var int */ - private $_width = null; + private $width = null; /** * Create a new table * - * @param string $insideOf - * @param int $pCount + * @param string $docPart + * @param int $docPartId * @param mixed $style */ - public function __construct($insideOf, $pCount, $style = null) + public function __construct($docPart, $docPartId, $style = null) { - $this->_insideOf = $insideOf; - $this->_pCount = $pCount; - - if (!is_null($style)) { - if (is_array($style)) { - $this->_style = new \PhpOffice\PhpWord\Style\Table(); - - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } else { - $this->_style = $style; - } - } + $this->docPart = $docPart; + $this->docPartId = $docPartId; + $this->style = $this->setStyle(new TableStyle(), $style); } /** @@ -88,8 +74,8 @@ class Table */ public function addRow($height = null, $style = null) { - $row = new Row($this->_insideOf, $this->_pCount, $height, $style); - $this->_rows[] = $row; + $row = new Row($this->docPart, $this->docPartId, $height, $style); + $this->rows[] = $row; return $row; } @@ -102,8 +88,8 @@ class Table */ public function addCell($width = null, $style = null) { - $i = count($this->_rows) - 1; - $cell = $this->_rows[$i]->addCell($width, $style); + $i = count($this->rows) - 1; + $cell = $this->rows[$i]->addCell($width, $style); return $cell; } @@ -114,17 +100,17 @@ class Table */ public function getRows() { - return $this->_rows; + return $this->rows; } /** * Get table style * - * @return \PhpOffice\PhpWord\Style\Table + * @return TableStyle */ public function getStyle() { - return $this->_style; + return $this->style; } /** @@ -134,7 +120,7 @@ class Table */ public function setWidth($width) { - $this->_width = $width; + $this->width = $width; } /** @@ -144,6 +130,6 @@ class Table */ public function getWidth() { - return $this->_width; + return $this->width; } } diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 75e1727e..620095b8 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text element */ -class Text +class Text extends Element { /** * Text content diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index 39f3ac16..adf144ba 100755 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text break element */ -class TextBreak +class TextBreak extends Element { /** * Paragraph style diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 5cf1a0c6..50b302de 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -36,18 +36,7 @@ class TextRun extends Container $this->container = 'textrun'; $this->docPart = $docPart; $this->docPartId = $docPartId; - // Set paragraph style - if (is_array($paragraphStyle)) { - $this->paragraphStyle = new Paragraph(); - foreach ($paragraphStyle as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->paragraphStyle->setStyleValue($key, $value); - } - } else { - $this->paragraphStyle = $paragraphStyle; - } + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } /** diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 3921d66c..2e7bf035 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -12,42 +12,42 @@ namespace PhpOffice\PhpWord\Element; /** * Title element */ -class Title +class Title extends Element { /** * Title Text content * * @var string */ - private $_text; + private $text; /** * Title depth * * @var int */ - private $_depth; + private $depth; /** * Title anchor * * @var int */ - private $_anchor; + private $anchor; /** * Title Bookmark ID * * @var int */ - private $_bookmarkId; + private $bookmarkId; /** * Title style * * @var string */ - private $_style; + private $style; /** @@ -60,11 +60,11 @@ class Title public function __construct($text, $depth = 1, $style = null) { if (!is_null($style)) { - $this->_style = $style; + $this->style = $style; } - $this->_text = $text; - $this->_depth = $depth; + $this->text = $text; + $this->depth = $depth; return $this; } @@ -76,7 +76,7 @@ class Title */ public function setAnchor($anchor) { - $this->_anchor = $anchor; + $this->anchor = $anchor; } /** @@ -86,7 +86,7 @@ class Title */ public function getAnchor() { - return $this->_anchor; + return $this->anchor; } /** @@ -96,7 +96,7 @@ class Title */ public function setBookmarkId($bookmarkId) { - $this->_bookmarkId = $bookmarkId; + $this->bookmarkId = $bookmarkId; } /** @@ -106,7 +106,7 @@ class Title */ public function getBookmarkId() { - return $this->_bookmarkId; + return $this->bookmarkId; } /** @@ -116,7 +116,7 @@ class Title */ public function getText() { - return $this->_text; + return $this->text; } /** @@ -126,6 +126,6 @@ class Title */ public function getStyle() { - return $this->_style; + return $this->style; } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index db8bd851..aec01ee3 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -614,7 +614,7 @@ class Base extends WriterPart $xmlWriter->endElement(); // w:rStyle $xmlWriter->endElement(); // w:rPr $xmlWriter->startElement('w:footnoteReference'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $xmlWriter->writeAttribute('w:id', $footnote->getRelationId()); $xmlWriter->endElement(); // w:footnoteReference $xmlWriter->endElement(); // w:r if (!$withoutP) { @@ -1173,13 +1173,16 @@ class Base extends WriterPart */ protected function writeContainerElements(XMLWriter $xmlWriter, Container $container) { + // Check allowed elements + $elmCommon = array('Text', 'Link', 'TextBreak', 'Image'); + $elmMainCell = array_merge($elmCommon, array('TextRun', 'ListItem', 'CheckBox')); $allowedElements = array( - 'Section' => array('Text', 'TextRun', 'Link', 'Title', 'TextBreak', 'ListItem', 'Table', 'Image', 'Object', 'CheckBox', 'Footnote', 'TOC'), - 'Header' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'CheckBox'), - 'Footer' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'CheckBox'), - 'Cell' => array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak', 'ListItem', 'Image', 'Object', 'CheckBox', 'Footnote'), - 'TextRun' => array('Text', 'Link', 'TextBreak', 'Image', 'Object', 'Footnote'), - 'Footnote' => array('Text', 'Link', 'TextBreak', 'Image', 'Object'), + 'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Object', 'Title', 'PageBreak', 'TOC')), + 'Header' => array_merge($elmMainCell, array('Table', 'PreserveText')), + 'Footer' => array_merge($elmMainCell, array('Table', 'PreserveText')), + 'Cell' => array_merge($elmMainCell, array('Object', 'PreserveText', 'Footnote')), + 'TextRun' => array_merge($elmCommon, array('Object', 'Footnote')), + 'Footnote' => array_merge($elmCommon, array('Object')), ); $containerName = get_class($container); $containerName = substr($containerName, strrpos($containerName, '\\') + 1); @@ -1189,6 +1192,7 @@ class Base extends WriterPart throw new Exception('Invalid container.'); } + // Loop through elements $elements = $container->getElements(); if (count($elements) > 0) { foreach ($elements as $element) { diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 406b1559..45c60eeb 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -89,7 +89,7 @@ class Footnotes extends Base protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) { $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); + $xmlWriter->writeAttribute('w:id', $footnote->getRelationId()); $xmlWriter->startElement('w:p'); // Paragraph style $styleParagraph = $footnote->getParagraphStyle(); diff --git a/tests/PhpWord/Tests/Element/FootnoteTest.php b/tests/PhpWord/Tests/Element/FootnoteTest.php index 21a18a4f..c2571afe 100644 --- a/tests/PhpWord/Tests/Element/FootnoteTest.php +++ b/tests/PhpWord/Tests/Element/FootnoteTest.php @@ -96,8 +96,8 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $oFootnote = new Footnote(); $iVal = rand(1, 1000); - $oFootnote->setReferenceId($iVal); - $this->assertEquals($oFootnote->getReferenceId(), $iVal); + $oFootnote->setRelationId($iVal); + $this->assertEquals($oFootnote->getRelationId(), $iVal); } /** From 1ebd26ddc6a228572689c97062fe0667f0a587d0 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 09:20:21 +0700 Subject: [PATCH 049/146] Fix some test error --- src/PhpWord/Element/Table.php | 1 + src/PhpWord/Writer/Word2007/Base.php | 4 ++-- tests/PhpWord/Tests/Element/CellTest.php | 11 ----------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 0035b897..72362c07 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -11,6 +11,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Style\Table as TableStyle; + /** * Table element */ diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index aec01ee3..0bf0056b 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1237,9 +1237,9 @@ class Base extends WriterPart $xmlWriter->startElement('w:' . $sides[$i]); if (!empty($colors)) { if (is_null($colors[$i]) && !empty($attributes)) { - if (array_key_exists('defaultColor', $attributes)) + if (array_key_exists('defaultColor', $attributes)) { $colors[$i] = $attributes['defaultColor']; - + } } $xmlWriter->writeAttribute('w:val', 'single'); $xmlWriter->writeAttribute('w:sz', $sizes[$i]); diff --git a/tests/PhpWord/Tests/Element/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php index be541935..a3507e3f 100644 --- a/tests/PhpWord/Tests/Element/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -42,17 +42,6 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oCell->getWidth(), null); } - /** - * New instance with string - */ - public function testConstructWithStyleString() - { - $iVal = rand(1, 1000); - $oCell = new Cell('section', $iVal, null, 'cellStyle'); - - $this->assertEquals($oCell->getStyle(), 'cellStyle'); - } - /** * Add text */ From 7c549f58020184f97b017c7a29b3746f3014cd29 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 10:13:13 +0700 Subject: [PATCH 050/146] DocBlock and use fixes --- src/PhpWord/Container/Container.php | 34 +---- src/PhpWord/Container/Header.php | 2 +- src/PhpWord/Container/Section.php | 4 +- src/PhpWord/DocumentProperties.php | 116 +++++++++--------- src/PhpWord/Element/Image.php | 10 +- src/PhpWord/Element/TextRun.php | 2 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/Media.php | 5 +- src/PhpWord/PhpWord.php | 40 +++--- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Shared/Font.php | 16 +-- src/PhpWord/Style/Font.php | 4 +- src/PhpWord/Style/Paragraph.php | 4 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Writer/ODText/Manifest.php | 1 - src/PhpWord/Writer/ODText/Meta.php | 1 - src/PhpWord/Writer/ODText/Styles.php | 1 - src/PhpWord/Writer/Word2007/Base.php | 3 +- src/PhpWord/Writer/Word2007/DocProps.php | 1 - src/PhpWord/Writer/Word2007/Document.php | 1 - src/PhpWord/Writer/Word2007/DocumentRels.php | 3 - src/PhpWord/Writer/Word2007/Footer.php | 1 - src/PhpWord/Writer/Word2007/Footnotes.php | 6 - src/PhpWord/Writer/Word2007/FootnotesRels.php | 3 - src/PhpWord/Writer/Word2007/Header.php | 1 - src/PhpWord/Writer/Word2007/Rels.php | 2 - 26 files changed, 110 insertions(+), 157 deletions(-) diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index 332f0c64..95fa186f 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -16,6 +16,7 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\TOC; use PhpOffice\PhpWord\Footnote as FootnoteCollection; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Element\Element; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\Link; @@ -34,7 +35,7 @@ use PhpOffice\PhpWord\Element\CheckBox; * * @since 0.9.2 */ -abstract class Container +abstract class Container extends Element { /** * Container type section|header|footer|cell|textrun|footnote @@ -53,7 +54,7 @@ abstract class Container /** * Elements collection * - * @var int + * @var array */ protected $elements = array(); @@ -487,37 +488,10 @@ abstract class Container return $this->addFootnote($paragraphStyle); } - /** - * Set style value - * - * Used by Footnote - * - * @param mixed $styleObject Style object, could be Font, Paragraph, Cell, Image - * @param mixed $styleValue - * @param boolean $returnObject Always return object - * @todo Remove duplicate with ..\Element\Element - */ - protected function setStyle($styleObject, $styleValue = null, $returnObject = false) - { - if (!is_null($styleValue) && is_array($styleValue)) { - foreach ($styleValue as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $styleObject->setStyleValue($key, $value); - } - $style = $styleObject; - } else { - $style = $returnObject ? $styleObject : $styleValue; - } - - return $style; - } - /** * Check if a method is allowed for the current container * - * @param string $element + * @param string $method * @return boolean */ private function checkValidity($method) diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Container/Header.php index 126f9198..ba31994d 100755 --- a/src/PhpWord/Container/Header.php +++ b/src/PhpWord/Container/Header.php @@ -36,7 +36,7 @@ class Header extends Container /** * Create new instance * - * @param int $sectionCount + * @param int $sectionId */ public function __construct($sectionId) { diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index b549280d..dfbc9a72 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -46,7 +46,7 @@ class Section extends Container * Create new instance * * @param int $sectionCount - * @param mixed $settings + * @param array $settings */ public function __construct($sectionCount, $settings = null) { @@ -132,7 +132,7 @@ class Section extends Container /** * Get Headers * - * @return array + * @return Header[] */ public function getHeaders() { diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 14ed3150..b1f02275 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -27,101 +27,101 @@ class DocumentProperties * * @var string */ - private $_creator; + private $creator; /** * LastModifiedBy * * @var string */ - private $_lastModifiedBy; + private $lastModifiedBy; /** * Created * * @var int */ - private $_created; + private $created; /** * Modified * * @var int */ - private $_modified; + private $modified; /** * Title * * @var string */ - private $_title; + private $title; /** * Description * * @var string */ - private $_description; + private $description; /** * Subject * * @var string */ - private $_subject; + private $subject; /** * Keywords * * @var string */ - private $_keywords; + private $keywords; /** * Category * * @var string */ - private $_category; + private $category; /** * Company * * @var string */ - private $_company; + private $company; /** * Manager * * @var string */ - private $_manager; + private $manager; /** * Custom Properties * * @var array */ - private $_customProperties = array(); + private $customProperties = array(); /** * Create new DocumentProperties */ public function __construct() { - $this->_creator = ''; - $this->_lastModifiedBy = $this->_creator; - $this->_created = time(); - $this->_modified = time(); - $this->_title = ''; - $this->_subject = ''; - $this->_description = ''; - $this->_keywords = ''; - $this->_category = ''; - $this->_company = ''; - $this->_manager = ''; + $this->creator = ''; + $this->lastModifiedBy = $this->creator; + $this->created = time(); + $this->modified = time(); + $this->title = ''; + $this->subject = ''; + $this->description = ''; + $this->keywords = ''; + $this->category = ''; + $this->company = ''; + $this->manager = ''; } /** @@ -131,7 +131,7 @@ class DocumentProperties */ public function getCreator() { - return $this->_creator; + return $this->creator; } /** @@ -142,7 +142,7 @@ class DocumentProperties */ public function setCreator($pValue = '') { - $this->_creator = $pValue; + $this->creator = $pValue; return $this; } @@ -153,7 +153,7 @@ class DocumentProperties */ public function getLastModifiedBy() { - return $this->_lastModifiedBy; + return $this->lastModifiedBy; } /** @@ -164,7 +164,7 @@ class DocumentProperties */ public function setLastModifiedBy($pValue = '') { - $this->_lastModifiedBy = $pValue; + $this->lastModifiedBy = $pValue; return $this; } @@ -175,7 +175,7 @@ class DocumentProperties */ public function getCreated() { - return $this->_created; + return $this->created; } /** @@ -189,7 +189,7 @@ class DocumentProperties if (is_null($pValue)) { $pValue = time(); } - $this->_created = $pValue; + $this->created = $pValue; return $this; } @@ -200,7 +200,7 @@ class DocumentProperties */ public function getModified() { - return $this->_modified; + return $this->modified; } /** @@ -214,7 +214,7 @@ class DocumentProperties if (is_null($pValue)) { $pValue = time(); } - $this->_modified = $pValue; + $this->modified = $pValue; return $this; } @@ -225,7 +225,7 @@ class DocumentProperties */ public function getTitle() { - return $this->_title; + return $this->title; } /** @@ -236,7 +236,7 @@ class DocumentProperties */ public function setTitle($pValue = '') { - $this->_title = $pValue; + $this->title = $pValue; return $this; } @@ -247,7 +247,7 @@ class DocumentProperties */ public function getDescription() { - return $this->_description; + return $this->description; } /** @@ -258,7 +258,7 @@ class DocumentProperties */ public function setDescription($pValue = '') { - $this->_description = $pValue; + $this->description = $pValue; return $this; } @@ -269,7 +269,7 @@ class DocumentProperties */ public function getSubject() { - return $this->_subject; + return $this->subject; } /** @@ -280,7 +280,7 @@ class DocumentProperties */ public function setSubject($pValue = '') { - $this->_subject = $pValue; + $this->subject = $pValue; return $this; } @@ -291,7 +291,7 @@ class DocumentProperties */ public function getKeywords() { - return $this->_keywords; + return $this->keywords; } /** @@ -302,7 +302,7 @@ class DocumentProperties */ public function setKeywords($pValue = '') { - $this->_keywords = $pValue; + $this->keywords = $pValue; return $this; } @@ -313,7 +313,7 @@ class DocumentProperties */ public function getCategory() { - return $this->_category; + return $this->category; } /** @@ -324,7 +324,7 @@ class DocumentProperties */ public function setCategory($pValue = '') { - $this->_category = $pValue; + $this->category = $pValue; return $this; } @@ -335,7 +335,7 @@ class DocumentProperties */ public function getCompany() { - return $this->_company; + return $this->company; } /** @@ -346,7 +346,7 @@ class DocumentProperties */ public function setCompany($pValue = '') { - $this->_company = $pValue; + $this->company = $pValue; return $this; } @@ -357,7 +357,7 @@ class DocumentProperties */ public function getManager() { - return $this->_manager; + return $this->manager; } /** @@ -368,7 +368,7 @@ class DocumentProperties */ public function setManager($pValue = '') { - $this->_manager = $pValue; + $this->manager = $pValue; return $this; } @@ -379,7 +379,7 @@ class DocumentProperties */ public function getCustomProperties() { - return array_keys($this->_customProperties); + return array_keys($this->customProperties); } /** @@ -390,7 +390,7 @@ class DocumentProperties */ public function isCustomPropertySet($propertyName) { - return isset($this->_customProperties[$propertyName]); + return isset($this->customProperties[$propertyName]); } /** @@ -401,8 +401,8 @@ class DocumentProperties */ public function getCustomPropertyValue($propertyName) { - if (isset($this->_customProperties[$propertyName])) { - return $this->_customProperties[$propertyName]['value']; + if (isset($this->customProperties[$propertyName])) { + return $this->customProperties[$propertyName]['value']; } } @@ -415,8 +415,8 @@ class DocumentProperties */ public function getCustomPropertyType($propertyName) { - if (isset($this->_customProperties[$propertyName])) { - return $this->_customProperties[$propertyName]['type']; + if (isset($this->customProperties[$propertyName])) { + return $this->customProperties[$propertyName]['type']; } } @@ -457,7 +457,7 @@ class DocumentProperties } } - $this->_customProperties[$propertyName] = array( + $this->customProperties[$propertyName] = array( 'value' => $propertyValue, 'type' => $propertyType ); @@ -465,11 +465,11 @@ class DocumentProperties } /** - * Convert document propery based on type + * Convert document property based on type * - * @param mixed $propertyValue - * @param string $propertyType - * @return mixed + * @param string $propertyValue + * @param string $propertyType + * @return mixed */ public static function convertProperty($propertyValue, $propertyType) { @@ -525,8 +525,8 @@ class DocumentProperties /** * Convert document property type * - * @param string $propertyType - * @return mixed + * @param string $propertyType + * @return string */ public static function convertPropertyType($propertyType) { diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 2631ec16..1824cec1 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -42,7 +42,7 @@ class Image extends Element /** * Is watermark * - * @var bool + * @var boolean */ private $isWatermark; @@ -77,7 +77,7 @@ class Image extends Element /** * Is memory image * - * @var string + * @var boolean */ private $isMemImage; @@ -86,7 +86,7 @@ class Image extends Element * * @param string $source * @param mixed $style - * @param bool $isWatermark + * @param boolean $isWatermark * @throws \PhpOffice\PhpWord\Exception\InvalidImageException * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException */ @@ -196,7 +196,7 @@ class Image extends Element /** * Get is watermark * - * @return int + * @return boolean */ public function getIsWatermark() { @@ -206,7 +206,7 @@ class Image extends Element /** * Set is watermark * - * @param bool $pValue + * @param boolean $pValue */ public function setIsWatermark($pValue) { diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 50b302de..4a980424 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -28,7 +28,7 @@ class TextRun extends Container * Create new instance * * @param string|array|Paragraph $paragraphStyle - * @param string $docPartType section|header|footer + * @param string $docPart section|header|footer * @param int $docPartId */ public function __construct($paragraphStyle = null, $docPart = 'section', $docPartId = 1) diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 2e7bf035..c8c29a35 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -55,7 +55,7 @@ class Title extends Element * * @param string $text * @param int $depth - * @param mixed $style + * @param string $style Name of the heading style, e.g. 'Heading1' */ public function __construct($text, $depth = 1, $style = null) { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index ccfa1649..99fd5c21 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -61,7 +61,7 @@ class Media * @param string $src * @param string $type * @param Image $image - * @return mixed + * @return integer|array */ public static function addSectionMediaElement($src, $type, Image $image = null) { @@ -115,7 +115,7 @@ class Media * Add new Section Link Element * * @param string $linkSrc - * @return mixed + * @return integer */ public static function addSectionLinkElement($linkSrc) { @@ -340,6 +340,7 @@ class Media * Get media elements * * @param string $container + * @param string $mediaType * @return int */ public static function getMediaElements($container, $mediaType = null) diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 89ee8d94..12143a3f 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -37,36 +37,36 @@ class PhpWord * * @var DocumentProperties */ - private $_documentProperties; + private $documentProperties; /** * Default font name * * @var string */ - private $_defaultFontName; + private $defaultFontName; /** * Default font size * @var int */ - private $_defaultFontSize; + private $defaultFontSize; /** * Collection of sections * * @var Section[] */ - private $_sections = array(); + private $sections = array(); /** * Create new */ public function __construct() { - $this->_documentProperties = new DocumentProperties(); - $this->_defaultFontName = self::DEFAULT_FONT_NAME; - $this->_defaultFontSize = self::DEFAULT_FONT_SIZE; + $this->documentProperties = new DocumentProperties(); + $this->defaultFontName = self::DEFAULT_FONT_NAME; + $this->defaultFontSize = self::DEFAULT_FONT_SIZE; } /** @@ -76,7 +76,7 @@ class PhpWord */ public function getDocumentProperties() { - return $this->_documentProperties; + return $this->documentProperties; } /** @@ -87,7 +87,7 @@ class PhpWord */ public function setDocumentProperties(DocumentProperties $documentProperties) { - $this->_documentProperties = $documentProperties; + $this->documentProperties = $documentProperties; return $this; } @@ -100,8 +100,8 @@ class PhpWord */ public function addSection($settings = null) { - $section = new Section(\count($this->_sections) + 1, $settings); - $this->_sections[] = $section; + $section = new Section(\count($this->sections) + 1, $settings); + $this->sections[] = $section; return $section; } @@ -113,7 +113,7 @@ class PhpWord */ public function getDefaultFontName() { - return $this->_defaultFontName; + return $this->defaultFontName; } /** @@ -123,17 +123,17 @@ class PhpWord */ public function setDefaultFontName($fontName) { - $this->_defaultFontName = $fontName; + $this->defaultFontName = $fontName; } /** * Get default font size * - * @return string + * @return integer */ public function getDefaultFontSize() { - return $this->_defaultFontSize; + return $this->defaultFontSize; } /** @@ -143,7 +143,7 @@ class PhpWord */ public function setDefaultFontSize($fontSize) { - $this->_defaultFontSize = $fontSize; + $this->defaultFontSize = $fontSize; } /** @@ -159,8 +159,8 @@ class PhpWord /** * Adds a paragraph style definition to styles.xml * - * @param $styleName string - * @param $styles array + * @param string $styleName + * @param array $styles */ public function addParagraphStyle($styleName, $styles) { @@ -170,7 +170,7 @@ class PhpWord /** * Adds a font style definition to styles.xml * - * @param $styleName string + * @param string $styleName * @param mixed $styleFont * @param mixed $styleParagraph */ @@ -221,7 +221,7 @@ class PhpWord */ public function getSections() { - return $this->_sections; + return $this->sections; } /** diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index be84d636..41bfd85f 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -64,7 +64,7 @@ class Word2007 extends Reader implements IReader * @param mixed $archive * @param string $fileName * @param bool $removeNamespace - * @return mixed + * @return string */ public function getFromZipArchive($archive, $fileName = '', $removeNamespace = false) { diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 23f368f6..f5317abb 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -17,8 +17,8 @@ class Font /** * Calculate an (approximate) pixel size, based on a font points size * - * @param int $fontSizeInPoints Font size (in points) - * @return int Font size (in pixels) + * @param int $fontSizeInPoints Font size (in points) + * @return int Font size (in pixels) */ public static function fontSizeToPixels($fontSizeInPoints = 12) { @@ -40,7 +40,7 @@ class Font * Calculate an (approximate) pixel size, based on centimeter size * * @param int $sizeInCm Font size (in centimeters) - * @return int Size (in pixels) + * @return double Size (in pixels) */ public static function centimeterSizeToPixels($sizeInCm = 1) { @@ -51,7 +51,7 @@ class Font * Convert centimeter to twip * * @param int $sizeInCm - * @return int + * @return double */ public static function centimeterSizeToTwips($sizeInCm = 1) { @@ -62,7 +62,7 @@ class Font * Convert inch to twip * * @param int $sizeInInch - * @return int + * @return double */ public static function inchSizeToTwips($sizeInInch = 1) { @@ -73,7 +73,7 @@ class Font * Convert pixel to twip * * @param int $sizeInPixel - * @return int + * @return double */ public static function pixelSizeToTwips($sizeInPixel = 1) { @@ -83,8 +83,8 @@ class Font /** * Calculate twip based on point size, used mainly for paragraph spacing * - * @param int|float $sizeInPoint Size in point - * @return int|float Size (in twips) + * @param integer $sizeInPoint Size in point + * @return integer Size (in twips) */ public static function pointSizeToTwips($sizeInPoint = 1) { diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index cc1f530c..69520804 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -447,7 +447,7 @@ class Font /** * Get foreground/highlight color * - * @return bool + * @return string */ public function getFgColor() { @@ -543,7 +543,7 @@ class Font /** * Get Font Content Type * - * @return bool + * @return string */ public function getHint() { diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index dbb04610..da1c8c05 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -188,7 +188,7 @@ class Paragraph /** * Get Space before Paragraph * - * @return string + * @return integer */ public function getSpaceBefore() { @@ -210,7 +210,7 @@ class Paragraph /** * Get Space after Paragraph * - * @return string + * @return integer */ public function getSpaceAfter() { diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index b6de4a81..bf744a3e 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -211,7 +211,7 @@ class Table /** * Get background * - * @return \PhpOffice\PhpWord\Style\Table + * @return string */ public function getBgColor() { diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index d7ab6cdc..3712cf66 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -11,7 +11,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText manifest part writer diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index 51647173..d0d593e2 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 4ae937e0..fa81ea9e 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 0bf0056b..6220b1f6 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1169,7 +1169,6 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param Container $container - * @param Container $textBreak Add text break when no element found */ protected function writeContainerElements(XMLWriter $xmlWriter, Container $container) { @@ -1224,9 +1223,9 @@ class Base extends WriterPart * Write margin or border * * @param XMLWriter $xmlWriter - * @param boolean $isBorder * @param array $sizes * @param array $colors + * @param array $attributes */ protected function writeMarginBorder(XMLWriter $xmlWriter, $sizes, $colors = array(), $attributes = array()) { diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 92c2fab8..46a74688 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 contenttypes part writer diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 60837794..3c0d6483 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -15,7 +15,6 @@ use PhpOffice\PhpWord\Container\Section; use PhpOffice\PhpWord\Element\PageBreak; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; /** * Word2007 document part writer diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php index 2129ea38..f5ca69fc 100755 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ b/src/PhpWord/Writer/Word2007/DocumentRels.php @@ -9,9 +9,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Shared\XMLWriter; - /** * Word2007 document rels part writer */ diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index d451bccd..4b075b97 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Container\Footer as FooterElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 footer part writer diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php index 45c60eeb..ac85929d 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Footnotes.php @@ -10,12 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Element\Footnote; -use PhpOffice\PhpWord\Element\Text; -use PhpOffice\PhpWord\Element\Link; -use PhpOffice\PhpWord\Element\Image; -use PhpOffice\PhpWord\Element\Object; -use PhpOffice\PhpWord\Element\TextBreak; -use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Shared\XMLWriter; /** diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php index 012062e1..e2cfd99f 100644 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ b/src/PhpWord/Writer/Word2007/FootnotesRels.php @@ -9,9 +9,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Shared\XMLWriter; - /** * Word2007 footnotes rel part writer */ diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 6b58c99f..3f649261 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Container\Header as HeaderElement; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 header part writer diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index 5619d978..d5476cf8 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -9,9 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 rels part writer From 1751ab09eec1de00f20cc64bdf5222b01a0589f0 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 11:34:06 +0700 Subject: [PATCH 051/146] Remove unused ZipStreamWrapper.php and cleanup some scripts --- CHANGELOG.md | 2 +- src/PhpWord/Container/Container.php | 24 ++- src/PhpWord/Container/Section.php | 2 + src/PhpWord/Element/Footnote.php | 2 + src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Footnote.php | 2 + src/PhpWord/IOFactory.php | 8 +- src/PhpWord/Media.php | 1 + src/PhpWord/PhpWord.php | 5 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 55 +++--- src/PhpWord/Shared/ZipStreamWrapper.php | 181 ------------------ src/PhpWord/Writer/ODText.php | 2 +- src/PhpWord/Writer/ODText/Content.php | 66 ++----- src/PhpWord/Writer/RTF.php | 36 ++-- src/PhpWord/Writer/Word2007.php | 40 ++-- src/PhpWord/Writer/Word2007/Base.php | 3 +- src/PhpWord/Writer/Word2007/ContentTypes.php | 10 +- src/PhpWord/Writer/Word2007/DocProps.php | 2 +- src/PhpWord/Writer/Word2007/Document.php | 2 +- tests/PhpWord/Tests/Container/FooterTest.php | 7 +- tests/PhpWord/Tests/Container/HeaderTest.php | 7 +- tests/PhpWord/Tests/Container/SectionTest.php | 3 +- tests/PhpWord/Tests/Element/CellTest.php | 7 +- 24 files changed, 135 insertions(+), 336 deletions(-) delete mode 100644 src/PhpWord/Shared/ZipStreamWrapper.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f1430f0a..26c9f071 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 - Reader: Rename AbstractReader > Reader - @ivanlanin - General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187 -- General: Remove legacy HashTable and all related properties/methods - @ivanlanin GH-187 +- General: Remove legacy HashTable and ZipStreamWrapper and all related properties/methods - @ivanlanin GH-187 - Container: Create new Container abstract class - @ivanlanin GH-187 - Element: Create new Element abstract class - @ivanlanin GH-187 diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index 95fa186f..0209b4c5 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -312,7 +312,9 @@ abstract class Container extends Element $rID = Media::addMediaElement('footnote', 'image', $src, $image); break; } - $image->setRelationId($rID); + if (is_int($rID)) { + $image->setRelationId($rID); + } $this->elements[] = $image; return $image; } else { @@ -366,7 +368,9 @@ abstract class Container extends Element $objectId = $data[1]; $object->setRelationId($rID); $object->setObjectId($objectId); - $object->setImageRelationId($rIDimg); + if (is_int($rIDimg)) { + $object->setImageRelationId($rIDimg); + } $this->elements[] = $object; return $object; } else { @@ -460,6 +464,7 @@ abstract class Container extends Element * @param string $src * @param mixed $style * @deprecated 0.9.0 + * @codeCoverageIgnore */ public function addMemoryImage($src, $style = null) { @@ -471,6 +476,7 @@ abstract class Container extends Element * * @param mixed $paragraphStyle * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function createTextRun($paragraphStyle = null) { @@ -482,6 +488,7 @@ abstract class Container extends Element * * @param mixed $paragraphStyle * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function createFootnote($paragraphStyle = null) { @@ -496,11 +503,12 @@ abstract class Container extends Element */ private function checkValidity($method) { + // Empty array means the element can be accepted by all containers $validContainers = array( - 'text' => 'all', - 'link' => 'all', - 'textbreak' => 'all', - 'image' => 'all', + 'text' => array(), + 'link' => array(), + 'textbreak' => array(), + 'image' => array(), 'textrun' => array('section', 'header', 'footer', 'cell'), 'listitem' => array('section', 'header', 'footer', 'cell'), 'checkbox' => array('section', 'header', 'footer', 'cell'), @@ -511,6 +519,8 @@ abstract class Container extends Element 'relationid' => array('header', 'footer', 'footnote'), 'title' => array('section'), ); + // Special condition, e.g. preservetext can only exists in cell when + // the cell is located in header or footer $validContainerInContainers = array( 'preservetext' => array(array('cell'), array('header', 'footer')), 'object' => array(array('cell', 'textrun'), array('section')), @@ -519,7 +529,7 @@ abstract class Container extends Element // Check if a method is valid for current container if (array_key_exists($method, $validContainers)) { - if (is_array($validContainers[$method])) { + if (!empty($validContainers[$method])) { if (!in_array($this->container, $validContainers[$method])) { throw new \BadMethodCallException(); } diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index dfbc9a72..5e39ee06 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -169,6 +169,7 @@ class Section extends Container * Create header * * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function createHeader() { @@ -179,6 +180,7 @@ class Section extends Container * Create footer * * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function createFooter() { diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 67cd5d9a..ff0c9960 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -50,6 +50,7 @@ class Footnote extends Container * * @return int * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function getReferenceId() { @@ -61,6 +62,7 @@ class Footnote extends Container * * @param int $refId * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function setReferenceId($refId) { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 72362c07..fb50caf2 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -41,7 +41,7 @@ class Table extends Element /** * Table holder count * - * @var array + * @var int */ private $docPartId; diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 2ec3d0b3..f656dc3a 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -65,6 +65,7 @@ class Footnote * @param string $linkSrc * @return int Reference ID * @deprecated 0.9.2 + * @codeCoverageIgnore */ public static function addFootnoteLinkElement($linkSrc) { @@ -76,6 +77,7 @@ class Footnote * * @return array * @deprecated 0.9.2 + * @codeCoverageIgnore */ public static function getFootnoteLinkElements() { diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index f99f7a00..eeafb057 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -22,9 +22,9 @@ abstract class IOFactory * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $name * @return \PhpOffice\PhpWord\Writer\IWriter - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws Exception */ - public static function createWriter(PhpWord $phpWord, $name) + public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { if ($name !== 'IWriter' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { throw new Exception("\"{$name}\" is not a valid writer."); @@ -39,9 +39,9 @@ abstract class IOFactory * * @param string $name * @return \PhpOffice\PhpWord\Reader\IReader - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws Exception */ - public static function createReader($name) + public static function createReader($name = 'Word2007') { if ($name !== 'IReader' && $name !== 'Word2007') { throw new Exception("\"{$name}\" is not a valid reader."); diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 99fd5c21..a026304d 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -194,6 +194,7 @@ class Media /** * Get Header Media Elements * + * @param string $prefix header|footer * @return array */ public static function getHeaderMediaElements($prefix = 'header') diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 12143a3f..420b9d7e 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -95,7 +95,7 @@ class PhpWord /** * Create new section * - * @param \PhpOffice\PhpWord\Container\Settings $settings + * @param array $settings * @return Section */ public function addSection($settings = null) @@ -243,9 +243,10 @@ class PhpWord /** * Create new section * - * @param \PhpOffice\PhpWord\Container\Settings $settings + * @param array $settings * @return Section * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function createSection($settings = null) { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 41bfd85f..175d7fd3 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -234,7 +234,7 @@ class Word2007 extends Reader implements IReader $styleName = (string)$elm->name['val']; if ($hasParagraphStyle) { $pStyle = $this->loadParagraphStyle($elm); - if (!$hasFontStyle) { + if (is_array($pStyle) && !$hasFontStyle) { $word->addParagraphStyle($styleName, $pStyle); } } diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index f207385c..7ef0889e 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -36,14 +36,14 @@ class ZipArchive * * @var string */ - private $_tempDir; + private $tempDir; /** * Zip Archive Stream Handle * * @var string */ - private $_zip; + private $zip; /** * Open a new zip archive @@ -53,8 +53,8 @@ class ZipArchive */ public function open($fileName) { - $this->_tempDir = sys_get_temp_dir(); - $this->_zip = new \PclZip($fileName); + $this->tempDir = sys_get_temp_dir(); + $this->zip = new \PclZip($fileName); return true; } @@ -83,13 +83,13 @@ class ZipArchive // To Rename the file while adding it to the zip we // need to create a temp file with the correct name if ($filenameParts['basename'] != $localnameParts['basename']) { - $temppath = $this->_tempDir . '/' . $localnameParts['basename']; + $temppath = $this->tempDir . '/' . $localnameParts['basename']; copy($filename, $temppath); $filename = $temppath; $filenameParts = pathinfo($temppath); } - $res = $this->_zip->add( + $res = $this->zip->add( $filename, PCLZIP_OPT_REMOVE_PATH, $filenameParts['dirname'], @@ -98,8 +98,7 @@ class ZipArchive ); if ($res == 0) { - throw new Exception("Error zipping files : " . $this->_zip->errorInfo(true)); - return false; + throw new Exception("Error zipping files : " . $this->zip->errorInfo(true)); } return true; @@ -116,25 +115,24 @@ class ZipArchive $filenameParts = pathinfo($localname); // Write $contents to a temp file - $handle = fopen($this->_tempDir . '/' . $filenameParts["basename"], "wb"); + $handle = fopen($this->tempDir . '/' . $filenameParts["basename"], "wb"); fwrite($handle, $contents); fclose($handle); // Add temp file to zip - $res = $this->_zip->add( - $this->_tempDir . '/' . $filenameParts["basename"], + $res = $this->zip->add( + $this->tempDir . '/' . $filenameParts["basename"], PCLZIP_OPT_REMOVE_PATH, - $this->_tempDir, + $this->tempDir, PCLZIP_OPT_ADD_PATH, $filenameParts["dirname"] ); if ($res == 0) { - throw new Exception("Error zipping files : " . $this->_zip->errorInfo(true)); - return false; + throw new Exception("Error zipping files : " . $this->zip->errorInfo(true)); } // Remove temp file - unlink($this->_tempDir . '/' . $filenameParts["basename"]); + unlink($this->tempDir . '/' . $filenameParts["basename"]); return true; } @@ -147,18 +145,18 @@ class ZipArchive */ public function locateName($fileName) { - $list = $this->_zip->listContent(); + $list = $this->zip->listContent(); $listCount = count($list); - $list_index = -1; + $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { if (strtolower($list[$i]["filename"]) == strtolower($fileName) || strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; + $listIndex = $i; break; } } - return ($list_index > -1); + return ($listIndex > -1); } /** @@ -169,31 +167,30 @@ class ZipArchive */ public function getFromName($fileName) { - $list = $this->_zip->listContent(); + $list = $this->zip->listContent(); $listCount = count($list); - $list_index = -1; + $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { if (strtolower($list[$i]["filename"]) == strtolower($fileName) || strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; + $listIndex = $i; break; } } - $extracted = ""; - if ($list_index != -1) { - $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); + if ($listIndex != -1) { + $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); } else { - $filename = substr($fileName, 1); - $list_index = -1; + $fileName = substr($fileName, 1); + $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { if (strtolower($list[$i]["filename"]) == strtolower($fileName) || strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { - $list_index = $i; + $listIndex = $i; break; } } - $extracted = $this->_zip->extractByIndex($list_index, PCLZIP_OPT_EXTRACT_AS_STRING); + $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); } if ((is_array($extracted)) && ($extracted != 0)) { $contents = $extracted[0]["content"]; diff --git a/src/PhpWord/Shared/ZipStreamWrapper.php b/src/PhpWord/Shared/ZipStreamWrapper.php deleted file mode 100644 index 23b69d84..00000000 --- a/src/PhpWord/Shared/ZipStreamWrapper.php +++ /dev/null @@ -1,181 +0,0 @@ -_archive = new $zipClass(); - $this->_archive->open($url['host']); - - $this->_fileNameInArchive = $url['fragment']; - $this->_position = 0; - $this->_data = $this->_archive->getFromName($this->_fileNameInArchive); - - return true; - } - - /** - * Stat stream - */ - public function streamStat() - { - return $this->_archive->statName($this->_fileNameInArchive); - } - - /** - * Read stream - * - * @param int $count - */ - public function streamRead($count) - { - $ret = substr($this->_data, $this->_position, $count); - $this->_position += strlen($ret); - return $ret; - } - - /** - * Tell stream - */ - public function streamTell() - { - return $this->_position; - } - - /** - * EOF stream - */ - public function streamEof() - { - return $this->_position >= strlen($this->_data); - } - - /** - * Seek stream - * - * @param int $offset - * @param mixed $whence - */ - public function streamSeek($offset, $whence) - { - switch ($whence) { - case \SEEK_SET: - if ($offset < strlen($this->_data) && $offset >= 0) { - $this->_position = $offset; - return true; - } else { - return false; - } - break; - - case \SEEK_CUR: - if ($offset >= 0) { - $this->_position += $offset; - return true; - } else { - return false; - } - break; - - case \SEEK_END: - if (strlen($this->_data) + $offset >= 0) { - $this->_position = strlen($this->_data) + $offset; - return true; - } else { - return false; - } - break; - - default: - return false; - } - } -} diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 04ec0bec..10e90dd3 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -23,9 +23,9 @@ use PhpOffice\PhpWord\Writer\ODText\Styles; */ class ODText extends Writer implements IWriter { - /** * Create new ODText writer + * * @param PhpWord $phpWord */ public function __construct(PhpWord $phpWord = null) diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index ccbdcfce..2a96e103 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -82,18 +82,18 @@ class Content extends WriterPart $xmlWriter->writeAttribute('office:version', '1.2'); // We firstly search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { $pSection = 0; $numPStyles = 0; $numFStyles = 0; - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); + $elements = $section->getElements(); - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { $fStyle = $element->getFontStyle(); $pStyle = $element->getParagraphStyle(); @@ -232,17 +232,13 @@ class Content extends WriterPart $xmlWriter->endElement(); $xmlWriter->endElement(); - $_sections = $phpWord->getSections(); - $countSections = count($_sections); - $pSection = 0; - + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { - foreach ($_sections as $section) { - $pSection++; + foreach ($sections as $section) { + $elements = $section->getElements(); - $_elements = $section->getElements(); - - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { $this->writeText($xmlWriter, $element); } elseif ($element instanceof TextRun) { @@ -269,12 +265,6 @@ class Content extends WriterPart $this->writeUnsupportedElement($xmlWriter, 'Element'); } } - - if ($pSection == $countSections) { - $this->writeEndSection($xmlWriter, $section); - } else { - $this->writeSection($xmlWriter, $section); - } } } $xmlWriter->endElement(); @@ -311,19 +301,21 @@ class Content extends WriterPart if (empty($styleFont)) { if (empty($styleParagraph)) { $xmlWriter->writeAttribute('text:style-name', 'P1'); - } else { - $xmlWriter->writeAttribute('text:style-name', $text->getParagraphStyle()); + } elseif (is_string($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', $styleParagraph); } $xmlWriter->writeRaw($text->getText()); } else { if (empty($styleParagraph)) { $xmlWriter->writeAttribute('text:style-name', 'Standard'); - } else { - $xmlWriter->writeAttribute('text:style-name', $text->getParagraphStyle()); + } elseif (is_string($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', $styleParagraph); } // text:span $xmlWriter->startElement('text:span'); - $xmlWriter->writeAttribute('text:style-name', $styleFont); + if (is_string($styleFont)) { + $xmlWriter->writeAttribute('text:style-name', $styleFont); + } $xmlWriter->writeRaw($text->getText()); $xmlWriter->endElement(); } @@ -359,35 +351,13 @@ class Content extends WriterPart * * @param XMLWriter $xmlWriter */ - protected function writeTextBreak(XMLWriter $xmlWriter = null) + protected function writeTextBreak(XMLWriter $xmlWriter) { $xmlWriter->startElement('text:p'); $xmlWriter->writeAttribute('text:style-name', 'Standard'); $xmlWriter->endElement(); } - // @codeCoverageIgnoreStart - /** - * Write end section - * - * @param XMLWriter $xmlWriter - * @param Section $section - */ - private function writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) - { - } - - /** - * Write section - * - * @param XMLWriter $xmlWriter - * @param Section $section - */ - private function writeSection(XMLWriter $xmlWriter = null, Section $section = null) - { - } - // @codeCoverageIgnoreEnd - /** * Write unsupported element * diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 6d693f17..a990575c 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -170,16 +170,16 @@ class RTF extends Writer implements IWriter } // Search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { $pSection = 0; - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); + $elements = $section->getElements(); - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { $fStyle = $element->getFontStyle(); @@ -227,16 +227,16 @@ class RTF extends Writer implements IWriter } // Search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { $pSection = 0; - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); + $elements = $section->getElements(); - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { $fStyle = $element->getFontStyle(); @@ -266,15 +266,15 @@ class RTF extends Writer implements IWriter $phpWord = $this->phpWord; $sRTFBody = ''; - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); $pSection = 0; if ($countSections > 0) { - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); - foreach ($_elements as $element) { + $elements = $section->getElements(); + foreach ($elements as $element) { if ($element instanceof Text) { $sRTFBody .= $this->getDataContentText($element); } elseif ($element instanceof TextBreak) { @@ -317,14 +317,12 @@ class RTF extends Writer implements IWriter $sRTFText = ''; $styleFont = $text->getFontStyle(); - $SfIsObject = ($styleFont instanceof Font) ? true : false; - if (!$SfIsObject) { + if (is_string($styleFont)) { $styleFont = Style::getStyle($styleFont); } $styleParagraph = $text->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - if (!$SpIsObject) { + if (is_string($styleParagraph)) { $styleParagraph = Style::getStyle($styleParagraph); } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 298b93cc..f86f30ac 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -104,8 +104,8 @@ class Word2007 extends Writer implements IWriter // Add section elements $sectionElements = array(); - $_secElements = Media::getSectionMediaElements(); - foreach ($_secElements as $element) { // loop through section media elements + $secElements = Media::getSectionMediaElements(); + foreach ($secElements as $element) { // loop through section media elements if ($element['type'] != 'hyperlink') { $this->addFileToPackage($objZip, $element); } @@ -145,33 +145,33 @@ class Word2007 extends Writer implements IWriter } // Process header/footer xml files - $_cHdrs = 0; - $_cFtrs = 0; + $cHdrs = 0; + $cFtrs = 0; $rID = Media::countSectionMediaElements() + 6; - $_sections = $this->phpWord->getSections(); + $sections = $this->phpWord->getSections(); $footers = array(); - foreach ($_sections as $section) { - $_headers = $section->getHeaders(); - foreach ($_headers as $index => &$_header) { - $_cHdrs++; - $_header->setRelationId(++$rID); - $hdrFile = "header{$_cHdrs}.xml"; + foreach ($sections as $section) { + $headers = $section->getHeaders(); + foreach ($headers as $index => &$header) { + $cHdrs++; + $header->setRelationId(++$rID); + $hdrFile = "header{$cHdrs}.xml"; $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); $objZip->addFromString( "word/{$hdrFile}", - $this->getWriterPart('header')->writeHeader($_header) + $this->getWriterPart('header')->writeHeader($header) ); } - $_footer = $section->getFooter(); - $footers[++$_cFtrs] = $_footer; - if (!is_null($_footer)) { - $_footer->setRelationId(++$rID); - $_footerCount = $_footer->getSectionId(); - $ftrFile = "footer{$_footerCount}.xml"; + $footer = $section->getFooter(); + $footers[++$cFtrs] = $footer; + if (!is_null($footer)) { + $footer->setRelationId(++$rID); + $footerCount = $footer->getSectionId(); + $ftrFile = "footer{$footerCount}.xml"; $sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID); $objZip->addFromString( "word/{$ftrFile}", - $this->getWriterPart('footer')->writeFooter($_footer) + $this->getWriterPart('footer')->writeFooter($footer) ); } } @@ -210,7 +210,7 @@ class Word2007 extends Writer implements IWriter $this->getWriterPart('contenttypes')->writeContentTypes( $this->imageTypes, $this->objectTypes, - $_cHdrs, + $cHdrs, $footers ) ); diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 6220b1f6..50bd6425 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -238,6 +238,7 @@ class Base extends WriterPart * * @param XMLWriter $xmlWriter * @param TextBreak $element + * @param boolean $withoutP */ protected function writeTextBreak(XMLWriter $xmlWriter, TextBreak $element = null, $withoutP = false) { @@ -1073,7 +1074,7 @@ class Base extends WriterPart * Write media rels (image, embeddings, hyperlink) * * @param XMLWriter $xmlWriter - * @param array mediaRels + * @param array $mediaRels */ protected function writeMediaRels(XMLWriter $xmlWriter, $mediaRels) { diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 86689823..98bf4e08 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -21,10 +21,10 @@ class ContentTypes extends WriterPart * Write [Content_Types].xml * @param array $imageTypes * @param array $objectTypes - * @param int $_cHdrs + * @param int $cHdrs * @param array $footers */ - public function writeContentTypes($imageTypes, $objectTypes, $_cHdrs, $footers) + public function writeContentTypes($imageTypes, $objectTypes, $cHdrs, $footers) { // Create XML writer $xmlWriter = $this->getXmlWriter(); @@ -133,7 +133,7 @@ class ContentTypes extends WriterPart 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml' ); - for ($i = 1; $i <= $_cHdrs; $i++) { + for ($i = 1; $i <= $cHdrs; $i++) { $this->writeOverrideContentType( $xmlWriter, '/word/header' . $i . '.xml', @@ -165,7 +165,7 @@ class ContentTypes extends WriterPart * @param string $pContentType Content type * @throws Exception */ - private function writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeDefaultContentType(XMLWriter $xmlWriter, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type @@ -186,7 +186,7 @@ class ContentTypes extends WriterPart * @param string $pContentType Content type * @throws Exception */ - private function writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') + private function writeOverrideContentType(XMLWriter $xmlWriter, $pPartname = '', $pContentType = '') { if ($pPartname != '' && $pContentType != '') { // Write content type diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index 46a74688..ceb5db04 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -111,7 +111,7 @@ class DocProps extends WriterPart * * @param PhpWord $phpWord */ - public function writeDocPropsCore(PhpWord $phpWord = null) + public function writeDocPropsCore(PhpWord $phpWord) { // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 3c0d6483..8bf46a0b 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -84,7 +84,7 @@ class Document extends Base { $xmlWriter->startElement('w:p'); $xmlWriter->startElement('w:pPr'); - $this->writeEndSection($xmlWriter, $section, 3); + $this->writeEndSection($xmlWriter, $section); $xmlWriter->endElement(); $xmlWriter->endElement(); } diff --git a/tests/PhpWord/Tests/Container/FooterTest.php b/tests/PhpWord/Tests/Container/FooterTest.php index ba712903..bcbf45a9 100644 --- a/tests/PhpWord/Tests/Container/FooterTest.php +++ b/tests/PhpWord/Tests/Container/FooterTest.php @@ -98,11 +98,10 @@ class FooterTest extends \PHPUnit_Framework_TestCase { $src = __DIR__ . "/../_files/images/earth.jpg"; $oFooter = new Footer(1); - $element1 = $oFooter->addImage($src); - $element2 = $oFooter->addMemoryImage($src); // @deprecated + $element = $oFooter->addImage($src); - $this->assertCount(2, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); + $this->assertCount(1, $oFooter->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php index dab67048..d7425bdc 100644 --- a/tests/PhpWord/Tests/Container/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -107,11 +107,10 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $src = __DIR__ . "/../_files/images/earth.jpg"; $oHeader = new Header(1); - $element1 = $oHeader->addImage($src); - $element2 = $oHeader->addMemoryImage($src); // @deprecated + $element = $oHeader->addImage($src); - $this->assertCount(2, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); + $this->assertCount(1, $oHeader->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php index a289df49..268f66e8 100644 --- a/tests/PhpWord/Tests/Container/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -84,7 +84,6 @@ class SectionTest extends \PHPUnit_Framework_TestCase $section->addListItem(utf8_decode('ä')); $section->addObject($objectSource); $section->addImage($imageSource); - $section->addMemoryImage($imageUrl); $section->addTitle(utf8_decode('ä'), 1); $section->addTextRun(); $section->addFootnote(); @@ -93,7 +92,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase $elementCollection = $section->getElements(); $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', - 'Table', 'ListItem', 'Object', 'Image', 'Image', + 'Table', 'ListItem', 'Object', 'Image', 'Title', 'TextRun', 'Footnote', 'CheckBox'); $i = 0; foreach ($elementTypes as $elementType) { diff --git a/tests/PhpWord/Tests/Element/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php index a3507e3f..3a2c3342 100644 --- a/tests/PhpWord/Tests/Element/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -123,11 +123,10 @@ class CellTest extends \PHPUnit_Framework_TestCase { $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('section', 1); - $element1 = $oCell->addImage($src); - $element2 = $oCell->addMemoryImage($src); // @deprecated + $element = $oCell->addImage($src); - $this->assertCount(2, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element1); + $this->assertCount(1, $oCell->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } /** From 0fc1a0626735558fd0234ae23bde0653b6a41079 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Thu, 3 Apr 2014 21:03:10 +0700 Subject: [PATCH 052/146] Merge all Word2007 relationships writer --- samples/Sample_07_TemplateCloneRow.php | 2 +- src/PhpWord/Writer/Word2007.php | 16 +- src/PhpWord/Writer/Word2007/Base.php | 48 ------ src/PhpWord/Writer/Word2007/DocumentRels.php | 74 --------- src/PhpWord/Writer/Word2007/FootnotesRels.php | 33 ---- src/PhpWord/Writer/Word2007/Rels.php | 156 +++++++++++++----- tests/PhpWord/Tests/Writer/Word2007Test.php | 2 - 7 files changed, 123 insertions(+), 208 deletions(-) delete mode 100755 src/PhpWord/Writer/Word2007/DocumentRels.php delete mode 100644 src/PhpWord/Writer/Word2007/FootnotesRels.php diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index 72464d84..789d22f0 100755 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -10,7 +10,7 @@ $document = $phpWord->loadTemplate('resources/Sample_07_TemplateCloneRow.docx'); // Variables on different parts of document $document->setValue('weekday', date('l')); // On section/content $document->setValue('time', date('H:i')); // On footer -$document->setValue('serverName', $_SERVER['SERVER_NAME']); // On header +$document->setValue('serverName', realpath(__DIR__)); // On header // Simple table $document->cloneRow('rowValue', 10); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index f86f30ac..7c87c2d4 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -15,14 +15,12 @@ use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; +use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\DocProps; use PhpOffice\PhpWord\Writer\Word2007\Document; -use PhpOffice\PhpWord\Writer\Word2007\DocumentRels; use PhpOffice\PhpWord\Writer\Word2007\Footer; use PhpOffice\PhpWord\Writer\Word2007\Footnotes; -use PhpOffice\PhpWord\Writer\Word2007\FootnotesRels; use PhpOffice\PhpWord\Writer\Word2007\Header; -use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\Styles; /** @@ -58,13 +56,11 @@ class Word2007 extends Writer implements IWriter $this->writerParts['contenttypes'] = new ContentTypes(); $this->writerParts['rels'] = new Rels(); $this->writerParts['docprops'] = new DocProps(); - $this->writerParts['documentrels'] = new DocumentRels(); $this->writerParts['document'] = new Document(); $this->writerParts['styles'] = new Styles(); $this->writerParts['header'] = new Header(); $this->writerParts['footer'] = new Footer(); $this->writerParts['footnotes'] = new Footnotes(); - $this->writerParts['footnotesrels'] = new FootnotesRels(); foreach ($this->writerParts as $writer) { $writer->setParentWriter($this); } @@ -118,7 +114,7 @@ class Word2007 extends Writer implements IWriter if (count($hdrMedia) > 0) { $objZip->addFromString( 'word/_rels/' . $hdrFile . '.xml.rels', - $this->getWriterPart('documentrels')->writeHeaderFooterRels($hdrMedia) + $this->getWriterPart('rels')->writeMediaRels($hdrMedia) ); foreach ($hdrMedia as $element) { if ($element['type'] != 'hyperlink') { @@ -134,7 +130,7 @@ class Word2007 extends Writer implements IWriter if (count($ftrMedia) > 0) { $objZip->addFromString( 'word/_rels/' . $ftrFile . '.xml.rels', - $this->getWriterPart('documentrels')->writeHeaderFooterRels($ftrMedia) + $this->getWriterPart('rels')->writeMediaRels($ftrMedia) ); foreach ($ftrMedia as $element) { if ($element['type'] != 'hyperlink') { @@ -198,7 +194,7 @@ class Word2007 extends Writer implements IWriter if (!empty($footnoteMedia)) { $objZip->addFromString( 'word/_rels/footnotes.xml.rels', - $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteMedia) + $this->getWriterPart('rels')->writeMediaRels($footnoteMedia) ); } } @@ -214,11 +210,11 @@ class Word2007 extends Writer implements IWriter $footers ) ); - $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeRelationships($this->phpWord)); + $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeMainRels()); $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->phpWord)); $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->phpWord)); + $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($sectionElements)); $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord)); - $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('documentrels')->writeDocumentRels($sectionElements)); $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); // Write static files diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 50bd6425..f8873152 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1070,54 +1070,6 @@ class Base extends WriterPart } } - /** - * Write media rels (image, embeddings, hyperlink) - * - * @param XMLWriter $xmlWriter - * @param array $mediaRels - */ - protected function writeMediaRels(XMLWriter $xmlWriter, $mediaRels) - { - $rTypePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; - foreach ($mediaRels as $mediaRel) { - $rId = $mediaRel['rID']; - $rType = $mediaRel['type']; - $rName = $mediaRel['target']; // file name - $targetMode = ($rType == 'hyperlink') ? 'External' : ''; - $rType = $rTypePrefix . ($rType == 'embeddings' ? 'oleObject' : $rType); - $this->writeRel($xmlWriter, $rId, $rType, $rName, $targetMode); - } - - } - - /** - * Write individual rels entry - * - * @param XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - protected function writeRel(XMLWriter $xmlWriter, $pId, $pType, $pTarget, $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } - /** * Write inline paragraph style * diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php deleted file mode 100755 index f5ca69fc..00000000 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ /dev/null @@ -1,74 +0,0 @@ -getXmlWriter(); - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Write static files - $staticFiles = array( - 'styles' => 'styles.xml', - 'numbering' => 'numbering.xml', - 'settings' => 'settings.xml', - 'theme' => 'theme/theme1.xml', - 'webSettings' => 'webSettings.xml', - 'fontTable' => 'fontTable.xml', - ); - $i = 0; - foreach ($staticFiles as $type => $file) { - $i++; - $schema = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $type; - $this->writeRel($xmlWriter, $i, $schema, $file); - } - - // Write media relationship (image, oleObject, hyperlink) - $this->writeMediaRels($xmlWriter, $relsCollection); - - $xmlWriter->endElement(); // Relationships - - return $xmlWriter->getData(); - } - - /** - * Write header footer rels word/_rels/*.xml.rels - * - * @param array $relsCollection - */ - public function writeHeaderFooterRels($relsCollection) - { - $xmlWriter = $this->getXmlWriter(); - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - $this->writeMediaRels($xmlWriter, $relsCollection); - $xmlWriter->endElement(); - - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php deleted file mode 100644 index e2cfd99f..00000000 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ /dev/null @@ -1,33 +0,0 @@ -getXmlWriter(); - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - $this->writeMediaRels($xmlWriter, $relsCollection); - $xmlWriter->endElement(); - - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index d5476cf8..8f684c47 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -9,58 +9,134 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLWriter; /** - * Word2007 rels part writer + * Word2007 relationship writer + * + * @since 0.9.2 */ -class Rels extends Base +class Rels extends WriterPart { + /** + * Base relationship URL + */ + const RELS_BASE = 'http://schemas.openxmlformats.org/'; + /** * Write _rels/.rels * * @param PhpWord $phpWord */ - public function writeRelationships(PhpWord $phpWord = null) + public function writeMainRels() { - // Create XML writer + $rels = array( + 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument', + 'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties', + 'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties', + ); $xmlWriter = $this->getXmlWriter(); - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - $relationId = 1; - - // Relationship word/document.xml - $this->writeRel( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', - 'word/document.xml' - ); - - // Relationship docProps/core.xml - $this->writeRel( - $xmlWriter, - ++$relationId, - 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', - 'docProps/core.xml' - ); - - // Relationship docProps/app.xml - $this->writeRel( - $xmlWriter, - ++$relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', - 'docProps/app.xml' - ); - - $xmlWriter->endElement(); + $this->writeRels($xmlWriter, $rels); return $xmlWriter->getData(); } + + /** + * Write word/_rels/document.xml.rels + * + * @param array $mediaRels + */ + public function writeDocRels($mediaRels) + { + $rels = array( + 'styles.xml' => 'officeDocument/2006/relationships/styles', + 'numbering.xml' => 'officeDocument/2006/relationships/numbering', + 'settings.xml' => 'officeDocument/2006/relationships/settings', + 'theme/theme1.xml' => 'officeDocument/2006/relationships/theme', + 'webSettings.xml' => 'officeDocument/2006/relationships/webSettings', + 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable', + ); + $xmlWriter = $this->getXmlWriter(); + $this->writeRels($xmlWriter, $rels, $mediaRels); + + return $xmlWriter->getData(); + } + + /** + * Write word/_rels/(header|footer|footnotes)*.xml.rels + * + * @param array $mediaRels + */ + public function writeMediaRels($mediaRels) + { + $xmlWriter = $this->getXmlWriter(); + $this->writeRels($xmlWriter, null, $mediaRels); + + return $xmlWriter->getData(); + } + + + /** + * Write relationships + * + * @param XMLWriter $xmlWriter + * @param null|array $rels + * @param null|array $mediaRels + * @param integer $id + */ + private function writeRels(XMLWriter $xmlWriter, $rels = null, $mediaRels = null, $id = 1) + { + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('Relationships'); + $xmlWriter->writeAttribute('xmlns', self::RELS_BASE . 'package/2006/relationships'); + if (is_array($rels)) { + foreach ($rels as $target => $type) { + $this->writeRel($xmlWriter, $id++, $type, $target); + } + } + if (is_array($mediaRels)) { + $typePrefix = 'officeDocument/2006/relationships/'; + foreach ($mediaRels as $mediaRel) { + $id = $mediaRel['rID']; + $type = $mediaRel['type']; + $target = $mediaRel['target']; // file name + $targetMode = ($type == 'hyperlink') ? 'External' : ''; + $type = $typePrefix . ($type == 'embeddings' ? 'oleObject' : $type); + $this->writeRel($xmlWriter, $id, $type, $target, $targetMode); + } + } + $xmlWriter->endElement(); + } + + /** + * Write individual rels entry + * + * Format: + * + * + * @param XMLWriter $xmlWriter + * @param int $id Relationship ID + * @param string $type Relationship type + * @param string $target Relationship target + * @param string $targetMode Relationship target mode + */ + private function writeRel(XMLWriter $xmlWriter, $id, $type, $target, $targetMode = '') + { + if ($type != '' && $target != '') { + if (strpos($id, 'rId') === false) { + $id = 'rId' . $id; + } + $xmlWriter->startElement('Relationship'); + $xmlWriter->writeAttribute('Id', $id); + $xmlWriter->writeAttribute('Type', self::RELS_BASE . $type); + $xmlWriter->writeAttribute('Target', $target); + if ($targetMode != '') { + $xmlWriter->writeAttribute('TargetMode', $targetMode); + } + $xmlWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); + } + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index 7b722a9c..fe80adb0 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -38,13 +38,11 @@ class Word2007Test extends \PHPUnit_Framework_TestCase 'ContentTypes', 'Rels', 'DocProps', - 'DocumentRels', 'Document', 'Styles', 'Header', 'Footer', 'Footnotes', - 'FootnotesRels', ); foreach ($writerParts as $part) { $this->assertInstanceOf( From e800d96cf9b4b0aa17e0f8d26fe629173cfc7e30 Mon Sep 17 00:00:00 2001 From: Diego Vieira Date: Fri, 4 Apr 2014 00:58:42 -0300 Subject: [PATCH 053/146] added clone, delete, replace block #165 Because I needed to clone, delete and replace some tables, I added those functions. --- samples/Sample_20_TemplateBlockClone.php | 18 +++++ samples/Sample_21_TemplateBlockDelete.php | 18 +++++ .../Sample_20_TemplateBlockClone.docx | Bin 0 -> 15293 bytes .../Sample_21_TemplateBlockDelete.docx | Bin 0 -> 15409 bytes src/PhpWord/Template.php | 64 ++++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 samples/Sample_20_TemplateBlockClone.php create mode 100644 samples/Sample_21_TemplateBlockDelete.php create mode 100644 samples/resources/Sample_20_TemplateBlockClone.docx create mode 100644 samples/resources/Sample_21_TemplateBlockDelete.docx diff --git a/samples/Sample_20_TemplateBlockClone.php b/samples/Sample_20_TemplateBlockClone.php new file mode 100644 index 00000000..781e1eea --- /dev/null +++ b/samples/Sample_20_TemplateBlockClone.php @@ -0,0 +1,18 @@ +loadTemplate('resources/Sample_20_TemplateBlockClone.docx'); + +// Will clone everything between ${tag} and ${/tag}, the number of times. By default, 1. +$document->cloneBlock('CLONEME', 3); + +$name = 'Sample_20_TemplateBlockClone.docx'; +echo date('H:i:s'), " Write to Word2007 format", EOL; +$document->saveAs($name); +rename($name, "results/{$name}"); + +include_once 'Sample_Footer.php'; diff --git a/samples/Sample_21_TemplateBlockDelete.php b/samples/Sample_21_TemplateBlockDelete.php new file mode 100644 index 00000000..6e6ddd28 --- /dev/null +++ b/samples/Sample_21_TemplateBlockDelete.php @@ -0,0 +1,18 @@ +loadTemplate('resources/Sample_21_TemplateBlockDelete.docx'); + +// Everything between ${tag} and ${/tag}, will be deleted/erased. +$document->deleteTemplateBlock('DELETEME'); + +$name = 'Sample_21_TemplateBlockDelete.docx'; +echo date('H:i:s'), " Write to Word2007 format", EOL; +$document->saveAs($name); +rename($name, "results/{$name}"); + +include_once 'Sample_Footer.php'; diff --git a/samples/resources/Sample_20_TemplateBlockClone.docx b/samples/resources/Sample_20_TemplateBlockClone.docx new file mode 100644 index 0000000000000000000000000000000000000000..1681174432420e04b284b59762ad71757594cfa2 GIT binary patch literal 15293 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 literal 0 HcmV?d00001 diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 9d9cc604..537e0343 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -257,6 +257,70 @@ class Template $this->_documentXML = $result; } + /** + * Clone a block + * + * @param mixed $blockname + * @param int $clones + * @param bool $replace + * @return null + */ + public function cloneBlock($blockname, $clones = 1, $replace = true) + { + $xmlBlock = null; + preg_match('/(<\?xml.*)(\${'.$blockname.'}<\/w:.*?p>)(.*)()/is', $this->_documentXML, $matchs); + + if (isset($matchs[3])) { + $xmlBlock = $matchs[3]; + $cloned = array(); + for($i = 1; $i <= $clones; $i++) { + $cloned[] = $xmlBlock; + } + + if ($replace) { + $this->_documentXML = str_replace($matchs[2].$matchs[3].$matchs[4], implode('', $cloned), $this->_documentXML); + } + } + return $xmlBlock; + } + + /** + * Replace a block + * + * @param mixed $blockname + * @param $replacement + */ + public function replaceBlock($blockname, $replacement) + { + $this->deleteTemplateBlock($blockname, $replacement); + } + + public function xmlpretty($xml) + { + $domxml = new DOMDocument('1.0'); + $domxml->preserveWhiteSpace = false; + $domxml->formatOutput = true; + $domxml->loadXML($xml); + $xml_string = $domxml->saveXML(); + return $xml_string; + } + + /** + * Delete a block of text + * + * @param mixed $blockname + * @param string $replacement + */ + public function deleteTemplateBlock($blockname, $replacement = '') + { + $xmlBlock = null; + preg_match('/(<\?xml.*)(\${'.$blockname.'}<\/w:.*?p>)(.*)()/is', $this->_documentXML, $matchs); + + if (isset($matchs[3])) { + $this->_documentXML = str_replace($matchs[2].$matchs[3].$matchs[4], $replacement, $this->_documentXML); + } + } + /** * Save XML to temporary file * From b75403f9a11049be92c03b37b7ecf18dd3a692ba Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 4 Apr 2014 00:29:57 +0700 Subject: [PATCH 054/146] Refactor Media, addObject to header and footer --- CHANGELOG.md | 6 +- docs/elements.rst | 2 +- samples/index.php | 2 +- src/PhpWord/Container/Container.php | 88 ++---- src/PhpWord/Element/Object.php | 1 - src/PhpWord/Media.php | 422 +++++++++++--------------- src/PhpWord/Shared/Drawing.php | 38 +-- src/PhpWord/Shared/String.php | 66 ++-- src/PhpWord/Shared/XMLWriter.php | 66 ++-- src/PhpWord/Writer/ODText/Content.php | 1 - src/PhpWord/Writer/RTF.php | 1 - src/PhpWord/Writer/Word2007.php | 144 ++++----- src/PhpWord/Writer/Word2007/Base.php | 10 +- src/PhpWord/Writer/Word2007/Rels.php | 13 +- tests/PhpWord/Tests/MediaTest.php | 66 ++-- 15 files changed, 381 insertions(+), 545 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26c9f071..80a6253a 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 - CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 - Link: Ability to add link in header/footer - @ivanlanin GH-187 -- Object: Ability to add object in textrun and footnote - @ivanlanin GH-187 +- Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 ### Bugfixes @@ -35,6 +35,9 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - `createSection` replaced by `addSection` - `Element\Footnote::getReferenceId` replaced by `Container\Container::getRelationId` - `Element\Footnote::setReferenceId` replaced by `Container\Container::setRelationId` +- `Footnote::addFootnoteLinkElement` replaced by `Media::addMediaElement` +- `Footnote::getFootnoteLinkElements` replaced by `Media::getMediaElements` +- All current methods on `Media` ### Miscellaneous @@ -45,6 +48,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - General: Remove legacy HashTable and ZipStreamWrapper and all related properties/methods - @ivanlanin GH-187 - Container: Create new Container abstract class - @ivanlanin GH-187 - Element: Create new Element abstract class - @ivanlanin GH-187 +- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/docs/elements.rst b/docs/elements.rst index da2038e5..abe3f7ba 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -31,7 +31,7 @@ the containers while the rows lists the elements. +-----+---------------+---------+--------+--------+------+----------+----------+ | 11 | Watermark | \- | v | \- | \- | \- | \- | +-----+---------------+---------+--------+--------+------+----------+----------+ -| 12 | Object | v | ? | ? | v | v | v | +| 12 | Object | v | v | v | v | v | v | +-----+---------------+---------+--------+--------+------+----------+----------+ | 13 | TOC | v | \- | \- | \- | \- | \- | +-----+---------------+---------+--------+--------+------+----------+----------+ diff --git a/samples/index.php b/samples/index.php index f4446ad4..451cf381 100644 --- a/samples/index.php +++ b/samples/index.php @@ -3,7 +3,7 @@ include_once 'Sample_Header.php'; if (!CLI) { ?>
-

Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Word (.docx), WordPad (.rtf), and Libre/OpenOffice Writer (.odt).

+

Welcome to PHPWord, a pure PHP library for reading and writing word processing documents, i.e. Word (.docx), WordPad (.rtf), and Libre/OpenOffice Writer (.odt).

Please use the menu above to browse PHPWord samples.

Fork us on Github! diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index 0209b4c5..fd08785e 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -143,30 +143,12 @@ abstract class Container extends Element public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) { $this->checkValidity('link'); - - $inSection = true; - if (!is_null($this->docPart)) { - $container = $this->docPart; - $containerId = $this->docPartId; - } else { - $container = $this->container; - $containerId = $this->containerId; - } - if ($container == 'header' || $container == 'footer') { - $container .= $containerId; - $inSection = false; - } elseif ($container == 'footnote') { - $inSection = false; - } + $elementDocPart = $this->checkElementDocPart(); $linkSrc = String::toUTF8($linkSrc); $linkName = String::toUTF8($linkName); $link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle); - if ($inSection) { - $rID = Media::addSectionLinkElement($linkSrc); - } else { - $rID = Media::addMediaElement($container, 'hyperlink', $linkSrc); - } + $rID = Media::addMediaElement($elementDocPart, 'link', $linkSrc); $link->setRelationId($rID); $this->elements[] = $link; @@ -286,32 +268,11 @@ abstract class Container extends Element public function addImage($src, $style = null, $isWatermark = false) { $this->checkValidity('image'); - if ($this->container == 'cell' || $this->container == 'textrun') { - $container = $this->docPart; - $containerId = $this->docPartId; - } else { - $container = $this->container; - $containerId = $this->containerId; - } + $elementDocPart = $this->checkElementDocPart(); $image = new Image($src, $style, $isWatermark); if (!is_null($image->getSource())) { - $rID = null; - switch ($container) { - case 'textrun': - case 'section': - $rID = Media::addSectionMediaElement($src, 'image', $image); - break; - case 'header': - $rID = Media::addHeaderMediaElement($containerId, $src, $image); - break; - case 'footer': - $rID = Media::addFooterMediaElement($containerId, $src, $image); - break; - case 'footnote': - $rID = Media::addMediaElement('footnote', 'image', $src, $image); - break; - } + $rID = Media::addMediaElement($elementDocPart, 'image', $src, $image); if (is_int($rID)) { $image->setRelationId($rID); } @@ -334,20 +295,8 @@ abstract class Container extends Element */ public function addObject($src, $style = null) { - $inSection = true; - if (!is_null($this->docPart)) { - $container = $this->docPart; - $containerId = $this->docPartId; - } else { - $container = $this->container; - $containerId = $this->containerId; - } - if ($container == 'header' || $container == 'footer') { - $container .= $containerId; - $inSection = false; - } elseif ($container == 'footnote') { - $inSection = false; - } + $this->checkValidity('object'); + $elementDocPart = $this->checkElementDocPart(); $object = new Object($src, $style); if (!is_null($object->getSource())) { @@ -357,13 +306,8 @@ abstract class Container extends Element $ext = substr($ext, 0, -1); } $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); - if ($inSection) { - $rIDimg = Media::addSectionMediaElement($icon, 'image', new Image($icon)); - $data = Media::addSectionMediaElement($src, 'oleObject'); - } else { - $rIDimg = Media::addMediaElement($container, 'image', $icon, new Image($icon)); - $data = Media::addMediaElement($container, 'embeddings', $src); - } + $rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon)); + $data = Media::addMediaElement($elementDocPart, 'object', $src); $rID = $data[0]; $objectId = $data[1]; $object->setRelationId($rID); @@ -509,11 +453,11 @@ abstract class Container extends Element 'link' => array(), 'textbreak' => array(), 'image' => array(), + 'object' => array(), 'textrun' => array('section', 'header', 'footer', 'cell'), 'listitem' => array('section', 'header', 'footer', 'cell'), 'checkbox' => array('section', 'header', 'footer', 'cell'), 'table' => array('section', 'header', 'footer'), - 'object' => array('section', 'textrun', 'cell', 'footnote'), 'footnote' => array('section', 'textrun', 'cell'), 'preservetext' => array('header', 'footer', 'cell'), 'relationid' => array('header', 'footer', 'footnote'), @@ -523,7 +467,6 @@ abstract class Container extends Element // the cell is located in header or footer $validContainerInContainers = array( 'preservetext' => array(array('cell'), array('header', 'footer')), - 'object' => array(array('cell', 'textrun'), array('section')), 'footnote' => array(array('cell', 'textrun'), array('section')), ); @@ -549,4 +492,17 @@ abstract class Container extends Element return true; } + + /** + * Return element location in document: section, headerx, or footerx + */ + private function checkElementDocPart() + { + $isCellTextrun = in_array($this->container, array('cell', 'textrun')); + $docPart = $isCellTextrun ? $this->docPart : $this->container; + $docPartId = $isCellTextrun ? $this->docPartId : $this->containerId; + $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); + + return $inHeaderFooter ? $docPart . $docPartId : $docPart; + } } diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 26207787..d885bfed 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -51,7 +51,6 @@ class Object extends Element */ private $objectId; - /** * Create a new Ole-Object Element * diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index a026304d..0a24d12a 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -16,31 +16,6 @@ use PhpOffice\PhpWord\Element\Image; */ class Media { - /** - * Section Media Elements - * - * @var array - */ - private static $sectionMedia = array( - 'images' => array(), - 'embeddings' => array(), - 'links' => array() - ); - - /** - * Header Media Elements - * - * @var array - */ - private static $headerMedia = array(); - - /** - * Footer Media Elements - * - * @var array - */ - private static $footerMedia = array(); - /** * Media elements * @@ -51,213 +26,23 @@ class Media /** * ObjectID Counter * - * @var int + * @var integer */ private static $objectId = 1325353440; - /** - * Add new Section Media Element - * - * @param string $src - * @param string $type - * @param Image $image - * @return integer|array - */ - public static function addSectionMediaElement($src, $type, Image $image = null) - { - $mediaId = md5($src); - $key = ($type === 'image') ? 'images' : 'embeddings'; - if (!array_key_exists($mediaId, self::$sectionMedia[$key])) { - $cImg = self::countSectionMediaElements('images'); - $cObj = self::countSectionMediaElements('embeddings'); - $rID = self::countSectionMediaElements() + 7; - $media = array(); - $folder = null; - $file = null; - if ($type === 'image') { - $cImg++; - $isMemImage = false; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $ext = $image->getImageExtension(); - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $folder = 'media'; - $file = $type . $cImg . '.' . strtolower($ext); - } elseif ($type === 'oleObject') { - $cObj++; - $folder = 'embeddings'; - $file = $type . $cObj . '.bin'; - } - $media['source'] = $src; - $media['target'] = "$folder/section_$file"; - $media['type'] = $type; - $media['rID'] = $rID; - self::$sectionMedia[$key][$mediaId] = $media; - if ($type === 'oleObject') { - return array($rID, ++self::$objectId); - } - return $rID; - } else { - if ($type === 'oleObject') { - $rID = self::$sectionMedia[$key][$mediaId]['rID']; - return array($rID, ++self::$objectId); - } - return self::$sectionMedia[$key][$mediaId]['rID']; - } - } - - /** - * Add new Section Link Element - * - * @param string $linkSrc - * @return integer - */ - public static function addSectionLinkElement($linkSrc) - { - $rID = self::countSectionMediaElements() + 7; - - $link = array(); - $link['target'] = $linkSrc; - $link['rID'] = $rID; - $link['type'] = 'hyperlink'; - - self::$sectionMedia['links'][] = $link; - - return $rID; - } - - /** - * Get Section Media Elements - * - * @param string $key - * @return array - */ - public static function getSectionMediaElements($key = null) - { - if (!is_null($key)) { - return self::$sectionMedia[$key]; - } - - $arrImages = self::$sectionMedia['images']; - $arrObjects = self::$sectionMedia['embeddings']; - $arrLinks = self::$sectionMedia['links']; - return array_merge($arrImages, $arrObjects, $arrLinks); - } - - /** - * Get Section Media Elements Count - * - * @param string $key - * @return int - */ - public static function countSectionMediaElements($key = null) - { - if (!is_null($key)) { - return count(self::$sectionMedia[$key]); - } - - $cImages = count(self::$sectionMedia['images']); - $cObjects = count(self::$sectionMedia['embeddings']); - $cLinks = count(self::$sectionMedia['links']); - return ($cImages + $cObjects + $cLinks); - } - - /** - * Add new Header Media Element - * - * @param int $headerCount - * @param string $src - * @param Image $image - * @return int - */ - public static function addHeaderMediaElement($headerCount, $src, Image $image = null) - { - return self::addMediaElement("header{$headerCount}", 'image', $src, $image); - } - - /** - * Get Header Media Elements Count - * - * @param string $key - * @return int - */ - public static function countHeaderMediaElements($key) - { - return self::countMediaElements($key); - } - - /** - * Get Header Media Elements - * - * @param string $prefix header|footer - * @return array - */ - public static function getHeaderMediaElements($prefix = 'header') - { - $mediaCollection = array(); - if (!empty(self::$media)) { - foreach (self::$media as $key => $val) { - if (substr($key, 0, 6) == $prefix) { - $mediaCollection[$key] = $val; - } - } - } - - return $mediaCollection; - } - - /** - * Add new Footer Media Element - * - * @param int $footerCount - * @param string $src - * @param Image $image - * @return int - */ - public static function addFooterMediaElement($footerCount, $src, Image $image = null) - { - return self::addMediaElement("footer{$footerCount}", 'image', $src, $image); - } - - /** - * Get Footer Media Elements Count - * - * @param string $key - * @return int - */ - public static function countFooterMediaElements($key) - { - return self::countMediaElements($key); - } - - /** - * Get Footer Media Elements - * - * @return array - */ - public static function getFooterMediaElements() - { - return self::getHeaderMediaElements('footer'); - } - /** * Add new media element * * @param string $container section|headerx|footerx|footnote - * @param string $mediaType image|embeddings|hyperlink + * @param string $mediaType image|object|link * @param string $source * @param Image $image - * @return int + * @return integer|array */ public static function addMediaElement($container, $mediaType, $source, Image $image = null) { - // Assign media Id and initiate media container if none exists - $mediaId = md5($source); + // Assign unique media Id and initiate media container if none exists + $mediaId = md5($container . $source); if (!array_key_exists($container, self::$media)) { self::$media[$container]= array(); } @@ -267,7 +52,7 @@ class Media $mediaCount = self::countMediaElements($container); $mediaTypeCount = self::countMediaElements($container, $mediaType); $mediaData = array(); - $relId = $mediaCount + 1; + $relId = ++$mediaCount; $target = null; $mediaTypeCount++; @@ -286,11 +71,11 @@ class Media } $target = "media/{$container}_image{$mediaTypeCount}.{$ext}"; // Objects - } elseif ($mediaType == 'embeddings') { + } elseif ($mediaType == 'object') { $file = "oleObject{$mediaTypeCount}.bin"; $target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin"; // Links - } elseif ($mediaType == 'hyperlink') { + } elseif ($mediaType == 'link') { $target = $source; } @@ -299,13 +84,13 @@ class Media $mediaData['type'] = $mediaType; $mediaData['rID'] = $relId; self::$media[$container][$mediaId] = $mediaData; - if ($mediaType === 'embeddings') { + if ($mediaType === 'object') { return array($relId, ++self::$objectId); } else { return $relId; } } else { - if ($mediaType === 'embeddings') { + if ($mediaType === 'object') { $relId = self::$media[$container][$mediaId]['rID']; return array($relId, ++self::$objectId); } else { @@ -317,20 +102,23 @@ class Media /** * Get media elements count * - * @param string $container - * @param string $mediaType - * @return int + * @param string $container section|headerx|footerx|footnote + * @param string $mediaType image|object|link + * @return integer */ public static function countMediaElements($container, $mediaType = null) { $mediaCount = 0; - foreach (self::$media[$container] as $mediaKey => $mediaData) { - if (!is_null($mediaType)) { - if ($mediaType == $mediaData['type']) { + + if (array_key_exists($container, self::$media)) { + foreach (self::$media[$container] as $mediaKey => $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaCount++; + } + } else { $mediaCount++; } - } else { - $mediaCount++; } } @@ -340,27 +128,171 @@ class Media /** * Get media elements * - * @param string $container - * @param string $mediaType - * @return int + * @param string $container section|headerx|footerx|footnote + * @param string $mediaType image|object|link + * @return array */ public static function getMediaElements($container, $mediaType = null) { - if (!array_key_exists($container, self::$media)) { - return false; - } - $mediaElements = array(); - foreach (self::$media[$container] as $mediaKey => $mediaData) { - if (!is_null($mediaType)) { - if ($mediaType == $mediaData['type']) { + + // If header/footer, search for headerx and footerx where x is number + if ($container == 'header' || $container == 'footer') { + foreach (self::$media as $key => $val) { + if (substr($key, 0, 6) == $container) { + $mediaElements[$key] = $val; + } + } + } else { + if (!array_key_exists($container, self::$media)) { + return $mediaElements; + } + foreach (self::$media[$container] as $mediaKey => $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaElements[$mediaKey] = $mediaData; + } + } else { $mediaElements[$mediaKey] = $mediaData; } - } else { - $mediaElements[$mediaKey] = $mediaData; } } return $mediaElements; } + + /** + * Add new Section Media Element + * + * @param string $src + * @param string $type + * @param Image $image + * @return integer|array + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function addSectionMediaElement($src, $type, Image $image = null) + { + return self::addMediaElement("section", $type, $src, $image); + } + + /** + * Add new Section Link Element + * + * @param string $linkSrc + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function addSectionLinkElement($linkSrc) + { + return self::addMediaElement('section', 'link', $linkSrc); + } + + /** + * Get Section Media Elements + * + * @param string $key + * @return array + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function getSectionMediaElements($key = null) + { + return self::getMediaElements('section', $key); + } + + /** + * Get Section Media Elements Count + * + * @param string $key + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function countSectionMediaElements($key = null) + { + return self::countMediaElements('section', $key); + } + + /** + * Add new Header Media Element + * + * @param integer $headerCount + * @param string $src + * @param Image $image + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function addHeaderMediaElement($headerCount, $src, Image $image = null) + { + return self::addMediaElement("header{$headerCount}", 'image', $src, $image); + } + + /** + * Get Header Media Elements Count + * + * @param string $key + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function countHeaderMediaElements($key) + { + return self::countMediaElements($key); + } + + /** + * Get Header Media Elements + * + * @param string $prefix header|footer + * @return array + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function getHeaderMediaElements() + { + return self::getMediaElements('header'); + } + + /** + * Add new Footer Media Element + * + * @param integer $footerCount + * @param string $src + * @param Image $image + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function addFooterMediaElement($footerCount, $src, Image $image = null) + { + return self::addMediaElement("footer{$footerCount}", 'image', $src, $image); + } + + /** + * Get Footer Media Elements Count + * + * @param string $key + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function countFooterMediaElements($key) + { + return self::countMediaElements($key); + } + + /** + * Get Footer Media Elements + * + * @return array + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public static function getFooterMediaElements() + { + return self::getMediaElements('footer'); + } } diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 4c04a5fc..58a6ee1a 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -17,8 +17,8 @@ class Drawing /** * Convert pixels to EMU * - * @param int $pValue Value in pixels - * @return int Value in EMU + * @param integer $pValue Value in pixels + * @return double Value in EMU */ public static function pixelsToEMU($pValue = 0) { @@ -28,8 +28,8 @@ class Drawing /** * Convert EMU to pixels * - * @param int $pValue Value in EMU - * @return int Value in pixels + * @param integer $pValue Value in EMU + * @return integer Value in pixels */ public static function EMUToPixels($pValue = 0) { @@ -43,8 +43,8 @@ class Drawing /** * Convert pixels to points * - * @param int $pValue Value in pixels - * @return int Value in points + * @param integer $pValue Value in pixels + * @return double Value in points */ public static function pixelsToPoints($pValue = 0) { @@ -54,8 +54,8 @@ class Drawing /** * Convert points width to pixels * - * @param int $pValue Value in points - * @return int Value in pixels + * @param integer $pValue Value in points + * @return integer Value in pixels */ public static function pointsToPixels($pValue = 0) { @@ -69,19 +69,19 @@ class Drawing /** * Convert degrees to angle * - * @param int $pValue Degrees - * @return int Angle + * @param integer $pValue Degrees + * @return integer Angle */ public static function degreesToAngle($pValue = 0) { - return (int)round($pValue * 60000); + return (integer)round($pValue * 60000); } /** * Convert angle to degrees * - * @param int $pValue Angle - * @return int Degrees + * @param integer $pValue Angle + * @return integer Degrees */ public static function angleToDegrees($pValue = 0) { @@ -95,8 +95,8 @@ class Drawing /** * Convert pixels to centimeters * - * @param int $pValue Value in pixels - * @return int Value in centimeters + * @param integer $pValue Value in pixels + * @return double Value in centimeters */ public static function pixelsToCentimeters($pValue = 0) { @@ -106,8 +106,8 @@ class Drawing /** * Convert centimeters width to pixels * - * @param int $pValue Value in centimeters - * @return int Value in pixels + * @param integer $pValue Value in centimeters + * @return integer Value in pixels */ public static function centimetersToPixels($pValue = 0) { @@ -121,8 +121,8 @@ class Drawing /** * Convert HTML hexadecimal to RGB * - * @param str $pValue HTML Color in hexadecimal - * @return array Value in RGB + * @param string $pValue HTML Color in hexadecimal + * @return array Value in RGB */ public static function htmlToRGB($pValue) { diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 9d298a66..e603f034 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -19,66 +19,36 @@ class String * * @var string[] */ - private static $_controlCharacters = array(); - - /** - * Build control characters array - */ - private static function _buildControlCharacters() - { - for ($i = 0; $i <= 19; ++$i) { - if ($i != 9 && $i != 10 && $i != 13) { - $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; - $replace = chr($i); - self::$_controlCharacters[$find] = $replace; - } - } - } + private static $controlCharacters = array(); /** * Convert from OpenXML escaped control character to PHP control character * - * Excel 2007 team: - * ---------------- - * That's correct, control characters are stored directly in the shared-strings table. - * We do encode characters that cannot be represented in XML using the following escape sequence: - * _xHHHH_ where H represents a hexadecimal character in the character's value... - * So you could end up with something like _x0008_ in a string (either in a cell value () - * element or in the shared string element. - * - * @param string $value Value to unescape - * @return string + * @param string $value Value to unescape + * @return string */ public static function controlCharacterOOXML2PHP($value = '') { - if (empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); } - return str_replace(array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value); + return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value); } /** * Convert from PHP control character to OpenXML escaped control character * - * Excel 2007 team: - * ---------------- - * That's correct, control characters are stored directly in the shared-strings table. - * We do encode characters that cannot be represented in XML using the following escape sequence: - * _xHHHH_ where H represents a hexadecimal character in the character's value... - * So you could end up with something like _x0008_ in a string (either in a cell value () - * element or in the shared string element. - * - * @param string $value Value to escape - * @return string + * @param string $value Value to escape + * @return string */ public static function controlCharacterPHP2OOXML($value = '') { - if (empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); } - return str_replace(array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value); + return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value); } /** @@ -106,4 +76,18 @@ class String return $value; } + + /** + * Build control characters array + */ + private static function buildControlCharacters() + { + for ($i = 0; $i <= 19; ++$i) { + if ($i != 9 && $i != 10 && $i != 13) { + $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; + $replace = chr($i); + self::$controlCharacters[$find] = $replace; + } + } + } } diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 16bb8334..d4e959bc 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -38,14 +38,14 @@ class XMLWriter * * @var \XMLWriter */ - private $_xmlWriter; + private $xmlWriter; /** * Temporary filename * * @var string */ - private $_tempFileName = ''; + private $tempFile = ''; /** * Create new XMLWriter @@ -56,30 +56,30 @@ class XMLWriter public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') { // Create internal XMLWriter - $this->_xmlWriter = new \XMLWriter(); + $this->xmlWriter = new \XMLWriter(); // Open temporary storage if ($pTemporaryStorage == self::STORAGE_MEMORY) { - $this->_xmlWriter->openMemory(); + $this->xmlWriter->openMemory(); } else { // Create temporary filename - $this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml'); + $this->tempFile = @tempnam($pTemporaryStorageFolder, 'xml'); // Open storage - if ($this->_xmlWriter->openUri($this->_tempFileName) === false) { + if ($this->xmlWriter->openUri($this->tempFile) === false) { // Fallback to memory... - $this->_xmlWriter->openMemory(); + $this->xmlWriter->openMemory(); } } // Set xml Compatibility $compatibility = Settings::getCompatibility(); if ($compatibility) { - $this->_xmlWriter->setIndent(false); - $this->_xmlWriter->setIndentString(''); + $this->xmlWriter->setIndent(false); + $this->xmlWriter->setIndentString(''); } else { - $this->_xmlWriter->setIndent(true); - $this->_xmlWriter->setIndentString(' '); + $this->xmlWriter->setIndent(true); + $this->xmlWriter->setIndentString(' '); } } @@ -89,26 +89,11 @@ class XMLWriter public function __destruct() { // Desctruct XMLWriter - unset($this->_xmlWriter); + unset($this->xmlWriter); // Unlink temporary files - if ($this->_tempFileName != '') { - @unlink($this->_tempFileName); - } - } - - /** - * Get written data - * - * @return string XML data - */ - public function getData() - { - if ($this->_tempFileName == '') { - return $this->_xmlWriter->outputMemory(true); - } else { - $this->_xmlWriter->flush(); - return file_get_contents($this->_tempFileName); + if ($this->tempFile != '') { + @unlink($this->tempFile); } } @@ -121,22 +106,37 @@ class XMLWriter public function __call($function, $args) { try { - @call_user_func_array(array($this->_xmlWriter, $function), $args); + @call_user_func_array(array($this->xmlWriter, $function), $args); } catch (\Exception $ex) { // Do nothing! } } + /** + * Get written data + * + * @return string XML data + */ + public function getData() + { + if ($this->tempFile == '') { + return $this->xmlWriter->outputMemory(true); + } else { + $this->xmlWriter->flush(); + return file_get_contents($this->tempFile); + } + } + /** * Fallback method for writeRaw, introduced in PHP 5.2 * * @param string $text - * @return string + * @return bool */ public function writeRaw($text) { - if (isset($this->_xmlWriter) && is_object($this->_xmlWriter) && (method_exists($this->_xmlWriter, 'writeRaw'))) { - return $this->_xmlWriter->writeRaw($text); + if (isset($this->xmlWriter) && is_object($this->xmlWriter) && (method_exists($this->xmlWriter, 'writeRaw'))) { + return $this->xmlWriter->writeRaw($text); } return $this->text($text); diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 2a96e103..0669bc41 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Container\Section; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\ListItem; diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index a990575c..8698365f 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -24,7 +24,6 @@ use PhpOffice\PhpWord\Element\Title; use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TOC; /** diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 7c87c2d4..352bb7ca 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -98,65 +98,40 @@ class Word2007 extends Writer implements IWriter } } - // Add section elements + // Add section media files $sectionElements = array(); - $secElements = Media::getSectionMediaElements(); - foreach ($secElements as $element) { // loop through section media elements - if ($element['type'] != 'hyperlink') { - $this->addFileToPackage($objZip, $element); - } - $sectionElements[] = $element; - } - // Add header relations & elements - $hdrElements = Media::getHeaderMediaElements(); - foreach ($hdrElements as $hdrFile => $hdrMedia) { - if (count($hdrMedia) > 0) { - $objZip->addFromString( - 'word/_rels/' . $hdrFile . '.xml.rels', - $this->getWriterPart('rels')->writeMediaRels($hdrMedia) - ); - foreach ($hdrMedia as $element) { - if ($element['type'] != 'hyperlink') { - $this->addFileToPackage($objZip, $element); - } - } + $secElements = Media::getMediaElements('section'); + if (!empty($secElements)) { + $this->addFilesToPackage($objZip, $secElements); + foreach ($secElements as $element) { + $sectionElements[] = $element; } } - // Add footer relations & elements - $ftrElements = Media::getFooterMediaElements(); - foreach ($ftrElements as $ftrFile => $ftrMedia) { - if (count($ftrMedia) > 0) { - $objZip->addFromString( - 'word/_rels/' . $ftrFile . '.xml.rels', - $this->getWriterPart('rels')->writeMediaRels($ftrMedia) - ); - foreach ($ftrMedia as $element) { - if ($element['type'] != 'hyperlink') { - $this->addFileToPackage($objZip, $element); - } - } - } - } + // Add header/footer media files & relations + $this->addHeaderFooterMedia($objZip, 'header'); + $this->addHeaderFooterMedia($objZip, 'footer'); - // Process header/footer xml files + // Add header/footer contents $cHdrs = 0; $cFtrs = 0; - $rID = Media::countSectionMediaElements() + 6; + $rID = Media::countMediaElements('section') + 6; // @see Rels::writeDocRels for 6 first elements $sections = $this->phpWord->getSections(); $footers = array(); foreach ($sections as $section) { $headers = $section->getHeaders(); - foreach ($headers as $index => &$header) { - $cHdrs++; - $header->setRelationId(++$rID); - $hdrFile = "header{$cHdrs}.xml"; - $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); - $objZip->addFromString( - "word/{$hdrFile}", - $this->getWriterPart('header')->writeHeader($header) - ); + if (!empty($headers)) { + foreach ($headers as $index => &$header) { + $cHdrs++; + $header->setRelationId(++$rID); + $hdrFile = "header{$cHdrs}.xml"; + $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); + $objZip->addFromString( + "word/{$hdrFile}", + $this->getWriterPart('header')->writeHeader($header) + ); + } } $footer = $section->getFooter(); $footers[++$cFtrs] = $footer; @@ -172,34 +147,23 @@ class Word2007 extends Writer implements IWriter } } - // Process footnotes + // Add footnotes media files, relations, and contents if (Footnote::countFootnoteElements() > 0) { - // Push to document.xml.rels $sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); - // Add footnote media to package $footnoteMedia = Media::getMediaElements('footnote'); - if (!empty($footnoteMedia)) { - foreach ($footnoteMedia as $media) { - if ($media['type'] != 'hyperlink') { - $this->addFileToPackage($objZip, $media); - } - } - } - // Write footnotes.xml - $objZip->addFromString( - 'word/footnotes.xml', - $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()) - ); - // Write footnotes.xml.rels + $this->addFilesToPackage($objZip, $footnoteMedia); if (!empty($footnoteMedia)) { $objZip->addFromString( 'word/_rels/footnotes.xml.rels', $this->getWriterPart('rels')->writeMediaRels($footnoteMedia) ); } + $objZip->addFromString( + 'word/footnotes.xml', + $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()) + ); } - // build docx file // Write dynamic files $objZip->addFromString( '[Content_Types].xml', @@ -288,21 +252,47 @@ class Word2007 extends Writer implements IWriter * @param mixed $objZip * @param mixed $element */ - private function addFileToPackage($objZip, $element) + private function addFilesToPackage($objZip, $elements) { - if (isset($element['isMemImage']) && $element['isMemImage']) { - $image = call_user_func($element['createfunction'], $element['source']); - ob_start(); - call_user_func($element['imagefunction'], $image); - $imageContents = ob_get_contents(); - ob_end_clean(); - $objZip->addFromString('word/' . $element['target'], $imageContents); - imagedestroy($image); + foreach ($elements as $element) { + if ($element['type'] == 'link') { + continue; + } + if (isset($element['isMemImage']) && $element['isMemImage']) { + $image = call_user_func($element['createfunction'], $element['source']); + ob_start(); + call_user_func($element['imagefunction'], $image); + $imageContents = ob_get_contents(); + ob_end_clean(); + $objZip->addFromString('word/' . $element['target'], $imageContents); + imagedestroy($image); - $this->checkContentTypes($element['source']); - } else { - $objZip->addFile($element['source'], 'word/' . $element['target']); - $this->checkContentTypes($element['source']); + $this->checkContentTypes($element['source']); + } else { + $objZip->addFile($element['source'], 'word/' . $element['target']); + $this->checkContentTypes($element['source']); + } + } + } + + /** + * Add header/footer media elements + */ + private function addHeaderFooterMedia($objZip, $docPart) + { + $elements = Media::getMediaElements($docPart); + if (!empty($elements)) { + foreach ($elements as $file => $media) { + if (count($media) > 0) { + $objZip->addFromString( + 'word/_rels/' . $file . '.xml.rels', + $this->getWriterPart('rels')->writeMediaRels($media) + ); + if (!empty($media)) { + $this->addFilesToPackage($objZip, $media); + } + } + } } } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index f8873152..10cabe49 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -1126,15 +1126,15 @@ class Base extends WriterPart protected function writeContainerElements(XMLWriter $xmlWriter, Container $container) { // Check allowed elements - $elmCommon = array('Text', 'Link', 'TextBreak', 'Image'); + $elmCommon = array('Text', 'Link', 'TextBreak', 'Image', 'Object'); $elmMainCell = array_merge($elmCommon, array('TextRun', 'ListItem', 'CheckBox')); $allowedElements = array( - 'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Object', 'Title', 'PageBreak', 'TOC')), + 'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Title', 'PageBreak', 'TOC')), 'Header' => array_merge($elmMainCell, array('Table', 'PreserveText')), 'Footer' => array_merge($elmMainCell, array('Table', 'PreserveText')), - 'Cell' => array_merge($elmMainCell, array('Object', 'PreserveText', 'Footnote')), - 'TextRun' => array_merge($elmCommon, array('Object', 'Footnote')), - 'Footnote' => array_merge($elmCommon, array('Object')), + 'Cell' => array_merge($elmMainCell, array('PreserveText', 'Footnote')), + 'TextRun' => array_merge($elmCommon, array('Footnote')), + 'Footnote' => $elmCommon, ); $containerName = get_class($container); $containerName = substr($containerName, strrpos($containerName, '\\') + 1); diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index 8f684c47..bbf0634c 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -26,8 +26,6 @@ class Rels extends WriterPart /** * Write _rels/.rels - * - * @param PhpWord $phpWord */ public function writeMainRels() { @@ -95,15 +93,14 @@ class Rels extends WriterPart $this->writeRel($xmlWriter, $id++, $type, $target); } } - if (is_array($mediaRels)) { - $typePrefix = 'officeDocument/2006/relationships/'; + if (!is_null($mediaRels) && is_array($mediaRels)) { + $mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'); foreach ($mediaRels as $mediaRel) { - $id = $mediaRel['rID']; $type = $mediaRel['type']; - $target = $mediaRel['target']; // file name + $type = array_key_exists($type, $mapping) ? $mapping[$type] : $type; + $target = $mediaRel['target']; $targetMode = ($type == 'hyperlink') ? 'External' : ''; - $type = $typePrefix . ($type == 'embeddings' ? 'oleObject' : $type); - $this->writeRel($xmlWriter, $id, $type, $target, $targetMode); + $this->writeRel($xmlWriter, $id++, "officeDocument/2006/relationships/{$type}", $target, $targetMode); } } $xmlWriter->endElement(); diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index a3e6ead5..b1a49059 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -25,7 +25,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testGetSectionMediaElementsWithNull() { - $this->assertEquals(Media::getSectionMediaElements(), array()); + $this->assertEquals(Media::getMediaElements('section'), array()); } /** @@ -33,31 +33,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testCountSectionMediaElementsWithNull() { - $this->assertEquals(Media::countSectionMediaElements(), 0); - } - - /** - * Get header media elements - */ - public function testGetHeaderMediaElements() - { - $this->assertAttributeEquals( - Media::getHeaderMediaElements(), - 'headerMedia', - 'PhpOffice\\PhpWord\\Media' - ); - } - - /** - * Get footer media elements - */ - public function testGetFooterMediaElements() - { - $this->assertAttributeEquals( - Media::getFooterMediaElements(), - 'footerMedia', - 'PhpOffice\\PhpWord\\Media' - ); + $this->assertEquals(Media::countMediaElements('section'), 0); } /** @@ -68,13 +44,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase $local = __DIR__ . "/_files/images/mars.jpg"; $object = __DIR__ . "/_files/documents/sheet.xls"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addSectionMediaElement($local, 'image', new Image($local)); - Media::addSectionMediaElement($local, 'image', new Image($local)); - Media::addSectionMediaElement($remote, 'image', new Image($remote)); - Media::addSectionMediaElement($object, 'oleObject'); - Media::addSectionMediaElement($object, 'oleObject'); + Media::addMediaElement('section', 'image', $local, new Image($local)); + Media::addMediaElement('section', 'image', $local, new Image($local)); + Media::addMediaElement('section', 'image', $remote, new Image($local)); + Media::addMediaElement('section', 'object', $object); + Media::addMediaElement('section', 'object', $object); - $this->assertEquals(3, Media::countSectionMediaElements()); + $this->assertEquals(3, Media::countMediaElements('section')); } /** @@ -82,12 +58,12 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testAddSectionLinkElement() { - $expected = Media::countSectionMediaElements() + 7; - $actual = Media::addSectionLinkElement('http://test.com'); + $expected = Media::countMediaElements('section') + 1; + $actual = Media::addMediaElement('section', 'link', 'http://test.com'); $this->assertEquals($expected, $actual); - $this->assertEquals(1, Media::countSectionMediaElements('links')); - $this->assertEquals(1, count(Media::getSectionMediaElements('links'))); + $this->assertEquals(1, Media::countMediaElements('section', 'link')); + $this->assertEquals(1, count(Media::getMediaElements('section', 'link'))); } /** @@ -97,13 +73,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addHeaderMediaElement(1, $local, new Image($local)); - Media::addHeaderMediaElement(1, $local, new Image($local)); - Media::addHeaderMediaElement(1, $remote, new Image($remote)); + Media::addMediaElement('header1', 'image', $local, new Image($local)); + Media::addMediaElement('header1', 'image', $local, new Image($local)); + Media::addMediaElement('header1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countHeaderMediaElements('header1')); + $this->assertEquals(2, Media::countMediaElements('header1')); $this->assertEquals(2, count(Media::getMediaElements('header1'))); - $this->assertFalse(Media::getMediaElements('header2')); + $this->assertEmpty(Media::getMediaElements('header2')); } /** @@ -113,10 +89,10 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addFooterMediaElement(1, $local, new Image($local)); - Media::addFooterMediaElement(1, $local, new Image($local)); - Media::addFooterMediaElement(1, $remote, new Image($remote)); + Media::addMediaElement('footer1', 'image', $local, new Image($local)); + Media::addMediaElement('footer1', 'image', $local, new Image($local)); + Media::addMediaElement('footer1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countFooterMediaElements('footer1')); + $this->assertEquals(2, Media::countMediaElements('footer1')); } } From d7c18fe4b8457c47bbb5c97ed2abf20b71977205 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 5 Apr 2014 00:08:00 +0700 Subject: [PATCH 055/146] Move OOXML specific feature from Media to Word2007\Base --- src/PhpWord/Container/Container.php | 98 ++++----- src/PhpWord/Container/Footer.php | 1 + src/PhpWord/Container/Header.php | 1 + src/PhpWord/Container/Section.php | 3 + src/PhpWord/Element/Cell.php | 3 +- src/PhpWord/Element/Element.php | 60 ++++++ src/PhpWord/Element/Object.php | 15 +- src/PhpWord/Element/Row.php | 20 +- src/PhpWord/Element/Table.php | 19 +- src/PhpWord/Element/TextRun.php | 4 +- src/PhpWord/Media.php | 23 +- src/PhpWord/Reader/Word2007.php | 4 +- src/PhpWord/Writer/Word2007.php | 5 +- src/PhpWord/Writer/Word2007/Base.php | 10 +- src/PhpWord/Writer/Word2007/ContentTypes.php | 215 +++++++------------ tests/PhpWord/Tests/Element/ObjectTest.php | 13 -- 16 files changed, 200 insertions(+), 294 deletions(-) diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index fd08785e..ec66a5a0 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -58,24 +58,6 @@ abstract class Container extends Element */ protected $elements = array(); - /** - * Document part type: section|header|footer - * - * Used by textrun and cell to determine where the element is located - * because it will affect the availability of other element, e.g. footnote - * will not be available when $docPart is header or footer. - * - * @var string - */ - protected $docPart = null; - - /** - * Document part Id - * - * @var int - */ - protected $docPartId; - /** * Relation Id * @@ -101,10 +83,11 @@ abstract class Container extends Element } $text = String::toUTF8($text); - $element = new Text($text, $fontStyle, $paragraphStyle); - $this->elements[] = $element; + $textObject = new Text($text, $fontStyle, $paragraphStyle); + $textObject->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->elements[] = $textObject; - return $element; + return $textObject; } /** @@ -117,15 +100,8 @@ abstract class Container extends Element { $this->checkValidity('textrun'); - if ($this->container == 'cell') { - $docPart = $this->docPart; - $docPartId = $this->docPartId; - } else { - $docPart = $this->container; - $docPartId = $this->containerId; - } - - $textRun = new TextRun($paragraphStyle, $docPart, $docPartId); + $textRun = new TextRun($paragraphStyle); + $textRun->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->elements[] = $textRun; return $textRun; @@ -145,9 +121,8 @@ abstract class Container extends Element $this->checkValidity('link'); $elementDocPart = $this->checkElementDocPart(); - $linkSrc = String::toUTF8($linkSrc); - $linkName = String::toUTF8($linkName); - $link = new Link($linkSrc, $linkName, $fontStyle, $paragraphStyle); + $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); + $link->setDocPart($this->getDocPart(), $this->getDocPartId()); $rID = Media::addMediaElement($elementDocPart, 'link', $linkSrc); $link->setRelationId($rID); $this->elements[] = $link; @@ -167,14 +142,15 @@ abstract class Container extends Element { $this->checkValidity('title'); - $text = String::toUTF8($text); $styles = Style::getStyles(); if (array_key_exists('Heading_' . $depth, $styles)) { $style = 'Heading' . $depth; } else { $style = null; } + $text = String::toUTF8($text); $title = new Title($text, $depth, $style); + $title->setDocPart($this->getDocPart(), $this->getDocPartId()); $data = TOC::addTitle($text, $depth); $anchor = $data[0]; $bookmarkId = $data[1]; @@ -197,11 +173,11 @@ abstract class Container extends Element { $this->checkValidity('preservetext'); - $text = String::toUTF8($text); - $ptext = new PreserveText($text, $fontStyle, $paragraphStyle); - $this->elements[] = $ptext; + $preserveText = new PreserveText(String::toUTF8($text), $fontStyle, $paragraphStyle); + $preserveText->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->elements[] = $preserveText; - return $ptext; + return $preserveText; } /** @@ -216,7 +192,9 @@ abstract class Container extends Element $this->checkValidity('textbreak'); for ($i = 1; $i <= $count; $i++) { - $this->elements[] = new TextBreak($fontStyle, $paragraphStyle); + $textBreak = new TextBreak($fontStyle, $paragraphStyle); + $textBreak->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->elements[] = $textBreak; } } @@ -234,8 +212,8 @@ abstract class Container extends Element { $this->checkValidity('listitem'); - $text = String::toUTF8($text); - $listItem = new ListItem($text, $depth, $fontStyle, $styleList, $paragraphStyle); + $listItem = new ListItem(String::toUTF8($text), $depth, $fontStyle, $styleList, $paragraphStyle); + $listItem->setDocPart($this->getDocPart(), $this->getDocPartId()); $this->elements[] = $listItem; return $listItem; @@ -251,7 +229,7 @@ abstract class Container extends Element { $this->checkValidity('table'); - $table = new Table($this->container, $this->containerId, $style); + $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); $this->elements[] = $table; return $table; @@ -271,11 +249,10 @@ abstract class Container extends Element $elementDocPart = $this->checkElementDocPart(); $image = new Image($src, $style, $isWatermark); + $image->setDocPart($this->getDocPart(), $this->getDocPartId()); if (!is_null($image->getSource())) { $rID = Media::addMediaElement($elementDocPart, 'image', $src, $image); - if (is_int($rID)) { - $image->setRelationId($rID); - } + $image->setRelationId($rID); $this->elements[] = $image; return $image; } else { @@ -299,6 +276,7 @@ abstract class Container extends Element $elementDocPart = $this->checkElementDocPart(); $object = new Object($src, $style); + $object->setDocPart($this->getDocPart(), $this->getDocPartId()); if (!is_null($object->getSource())) { $inf = pathinfo($src); $ext = $inf['extension']; @@ -306,15 +284,10 @@ abstract class Container extends Element $ext = substr($ext, 0, -1); } $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); - $rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon)); - $data = Media::addMediaElement($elementDocPart, 'object', $src); - $rID = $data[0]; - $objectId = $data[1]; + $rID = Media::addMediaElement($elementDocPart, 'object', $src); $object->setRelationId($rID); - $object->setObjectId($objectId); - if (is_int($rIDimg)) { - $object->setImageRelationId($rIDimg); - } + $rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon)); + $object->setImageRelationId($rIDimg); $this->elements[] = $object; return $object; } else { @@ -334,6 +307,7 @@ abstract class Container extends Element $footnote = new FootnoteElement($paragraphStyle); $refID = FootnoteCollection::addFootnoteElement($footnote); + $footnote->setDocPart($this->getDocPart(), $this->getDocPartId()); $footnote->setRelationId($refID); $this->elements[] = $footnote; @@ -353,17 +327,17 @@ abstract class Container extends Element { $this->checkValidity('checkbox'); - $name = String::toUTF8($name); - $text = String::toUTF8($text); - $element = new CheckBox($name, $text, $fontStyle, $paragraphStyle); - $this->elements[] = $element; + $checkBox = new CheckBox(String::toUTF8($name), String::toUTF8($text), $fontStyle, $paragraphStyle); + $checkBox->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->elements[] = $checkBox; - return $element; + return $checkBox; } /** * Get section number - * getFooterCount + * + * @return array */ public function getSectionId() { @@ -484,7 +458,7 @@ abstract class Container extends Element $containers = $rules[0]; $allowedDocParts = $rules[1]; foreach ($containers as $container) { - if ($this->container == $container && !in_array($this->docPart, $allowedDocParts)) { + if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { throw new \BadMethodCallException(); } } @@ -499,8 +473,8 @@ abstract class Container extends Element private function checkElementDocPart() { $isCellTextrun = in_array($this->container, array('cell', 'textrun')); - $docPart = $isCellTextrun ? $this->docPart : $this->container; - $docPartId = $isCellTextrun ? $this->docPartId : $this->containerId; + $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; + $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->containerId; $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); return $inHeaderFooter ? $docPart . $docPartId : $docPart; diff --git a/src/PhpWord/Container/Footer.php b/src/PhpWord/Container/Footer.php index 56f06383..440b3b4e 100755 --- a/src/PhpWord/Container/Footer.php +++ b/src/PhpWord/Container/Footer.php @@ -23,5 +23,6 @@ class Footer extends Container { $this->container = 'footer'; $this->containerId = $sectionId; + $this->setDocPart($this->container, $this->containerId); } } diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Container/Header.php index ba31994d..39c6ca98 100755 --- a/src/PhpWord/Container/Header.php +++ b/src/PhpWord/Container/Header.php @@ -42,6 +42,7 @@ class Header extends Container { $this->container = 'header'; $this->containerId = $sectionId; + $this->setDocPart($this->container, $this->containerId); } /** diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index 5e39ee06..69edec41 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -52,6 +52,7 @@ class Section extends Container { $this->container = 'section'; $this->containerId = $sectionCount; + $this->setDocPart($this->container, $this->containerId); $this->settings = new Settings(); $this->setSettings($settings); } @@ -168,6 +169,7 @@ class Section extends Container /** * Create header * + * @return Header * @deprecated 0.9.2 * @codeCoverageIgnore */ @@ -179,6 +181,7 @@ class Section extends Container /** * Create footer * + * @return Footer * @deprecated 0.9.2 * @codeCoverageIgnore */ diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 61e2fa4c..5e035fb7 100755 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -42,8 +42,7 @@ class Cell extends Container public function __construct($docPart, $docPartId, $width = null, $style = null) { $this->container = 'cell'; - $this->docPart = $docPart; - $this->docPartId = $docPartId; + $this->setDocPart($docPart, $docPartId); $this->width = $width; $this->cellStyle = $this->setStyle(new CellStyle(), $style, true); } diff --git a/src/PhpWord/Element/Element.php b/src/PhpWord/Element/Element.php index b94a62c3..b3565775 100644 --- a/src/PhpWord/Element/Element.php +++ b/src/PhpWord/Element/Element.php @@ -16,6 +16,24 @@ namespace PhpOffice\PhpWord\Element; */ abstract class Element { + /** + * Document part type: section|header|footer + * + * Used by textrun and cell container to determine where the element is + * located because it will affect the availability of other element, + * e.g. footnote will not be available when $docPart is header or footer. + * + * @var string + */ + private $docPart = 'section'; + + /** + * Document part Id + * + * @var integer + */ + private $docPartId = 1; + /** * Set style value * @@ -39,4 +57,46 @@ abstract class Element return $style; } + + /** + * Set doc part + * + * @param string $docPart + * @param integer $docPartId + */ + public function setDocPart($docPart, $docPartId = 1) + { + $this->docPart = $docPart; + $this->docPartId = $docPartId; + } + + /** + * Get doc part + * + * @return string + */ + public function getDocPart() + { + return $this->docPart; + } + + /** + * Get doc part Id + * + * @return integer + */ + public function getDocPartId() + { + return $this->docPartId; + } + + /** + * Check if element is located in section doc part (as opposed to header/footer) + * + * @return boolean + */ + public function isInSection() + { + return ($this->docPart == 'section'); + } } diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index d885bfed..5716b7e6 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -44,13 +44,6 @@ class Object extends Element */ private $imageRelationId; - /** - * Object ID - * - * @var int - */ - private $objectId; - /** * Create a new Ole-Object Element * @@ -135,19 +128,23 @@ class Object extends Element * Get Object ID * * @return int + * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function getObjectId() { - return $this->objectId; + return $this->relationId + 1325353440; } /** * Set Object ID * * @param int $objId + * @deprecated 0.9.2 + * @codeCoverageIgnore */ public function setObjectId($objId) { - $this->objectId = $objId; + $this->relationId = $objId; } } diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 25357062..53990850 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -37,21 +37,6 @@ class Row extends Element */ private $cells = array(); - /** - * Table holder - * - * @var string - */ - private $docPart; - - /** - * Section/Header/Footer count - * - * @var int - */ - private $docPartId; - - /** * Create a new table row * @@ -62,8 +47,7 @@ class Row extends Element */ public function __construct($docPart, $docPartId, $height = null, $style = null) { - $this->docPart = $docPart; - $this->docPartId = $docPartId; + $this->setDocPart($docPart, $docPartId); $this->height = $height; $this->style = $this->setStyle(new RowStyle(), $style, true); } @@ -76,7 +60,7 @@ class Row extends Element */ public function addCell($width = null, $style = null) { - $cell = new Cell($this->docPart, $this->docPartId, $width, $style); + $cell = new Cell($this->getDocPart(), $this->getDocPartId(), $width, $style); $this->cells[] = $cell; return $cell; } diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index fb50caf2..5808a065 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -31,20 +31,6 @@ class Table extends Element */ private $rows = array(); - /** - * Table holder - * - * @var string - */ - private $docPart = null; - - /** - * Table holder count - * - * @var int - */ - private $docPartId; - /** * Table width * @@ -62,8 +48,7 @@ class Table extends Element */ public function __construct($docPart, $docPartId, $style = null) { - $this->docPart = $docPart; - $this->docPartId = $docPartId; + $this->setDocPart($docPart, $docPartId); $this->style = $this->setStyle(new TableStyle(), $style); } @@ -75,7 +60,7 @@ class Table extends Element */ public function addRow($height = null, $style = null) { - $row = new Row($this->docPart, $this->docPartId, $height, $style); + $row = new Row($this->getDocPart(), $this->getDocPartId(), $height, $style); $this->rows[] = $row; return $row; } diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 4a980424..794ad230 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -31,11 +31,9 @@ class TextRun extends Container * @param string $docPart section|header|footer * @param int $docPartId */ - public function __construct($paragraphStyle = null, $docPart = 'section', $docPartId = 1) + public function __construct($paragraphStyle = null) { $this->container = 'textrun'; - $this->docPart = $docPart; - $this->docPartId = $docPartId; $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 0a24d12a..d354e399 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -23,13 +23,6 @@ class Media */ private static $media = array(); - /** - * ObjectID Counter - * - * @var integer - */ - private static $objectId = 1325353440; - /** * Add new media element * @@ -37,7 +30,7 @@ class Media * @param string $mediaType image|object|link * @param string $source * @param Image $image - * @return integer|array + * @return integer */ public static function addMediaElement($container, $mediaType, $source, Image $image = null) { @@ -84,18 +77,9 @@ class Media $mediaData['type'] = $mediaType; $mediaData['rID'] = $relId; self::$media[$container][$mediaId] = $mediaData; - if ($mediaType === 'object') { - return array($relId, ++self::$objectId); - } else { - return $relId; - } + return $relId; } else { - if ($mediaType === 'object') { - $relId = self::$media[$container][$mediaId]['rID']; - return array($relId, ++self::$objectId); - } else { - return self::$media[$container][$mediaId]['rID']; - } + return self::$media[$container][$mediaId]['rID']; } } @@ -246,7 +230,6 @@ class Media /** * Get Header Media Elements * - * @param string $prefix header|footer * @return array * @deprecated 0.9.2 * @codeCoverageIgnore diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 175d7fd3..f8add95a 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -428,8 +428,8 @@ class Word2007 extends Reader implements IReader * Return item of array * * @param array $array - * @param mixed $key - * @return mixed|null + * @param integer $key + * @return string */ private static function arrayItem($array, $key = 0) { diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 352bb7ca..084deb8d 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -250,7 +250,7 @@ class Word2007 extends Writer implements IWriter * Check content types * * @param mixed $objZip - * @param mixed $element + * @param mixed $elements */ private function addFilesToPackage($objZip, $elements) { @@ -277,6 +277,9 @@ class Word2007 extends Writer implements IWriter /** * Add header/footer media elements + * + * @param mixed $objZip + * @param string $docPart */ private function addHeaderFooterMedia($objZip, $docPart) { diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 10cabe49..762bc7ea 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -93,7 +93,7 @@ class Base extends WriterPart */ protected function writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) { - $rID = $link->getRelationId(); + $rID = $link->getRelationId() + ($link->isInSection() ? 6 : 0); $linkName = $link->getLinkName(); if (is_null($linkName)) { $linkName = $link->getLinkSrc(); @@ -417,7 +417,7 @@ class Base extends WriterPart */ protected function writeImage(XMLWriter $xmlWriter, Image $image, $withoutP = false) { - $rId = $image->getRelationId(); + $rId = $image->getRelationId() + ($image->isInSection() ? 6 : 0); $style = $image->getStyle(); $width = $style->getWidth(); @@ -550,10 +550,10 @@ class Base extends WriterPart */ protected function writeObject(XMLWriter $xmlWriter, Object $object, $withoutP = false) { - $rIdObject = $object->getRelationId(); - $rIdImage = $object->getImageRelationId(); + $rIdObject = $object->getRelationId() + ($object->isInSection() ? 6 : 0); + $rIdImage = $object->getImageRelationId() + ($object->isInSection() ? 6 : 0); $shapeId = md5($rIdObject . '_' . $rIdImage); - $objectId = $object->getObjectId(); + $objectId = $object->getRelationId() + 1325353440; $style = $object->getStyle(); $align = $style->getAlign(); diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 98bf4e08..9e6853d0 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -26,173 +26,76 @@ class ContentTypes extends WriterPart */ public function writeContentTypes($imageTypes, $objectTypes, $cHdrs, $footers) { - // Create XML writer - $xmlWriter = $this->getXmlWriter(); - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $OpenXMLPrefix = 'application/vnd.openxmlformats-'; + $WordMLPrefix = $OpenXMLPrefix . 'officedocument.wordprocessingml.'; - // Types - $xmlWriter->startElement('Types'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); + $defaults = array( + 'rels' => $OpenXMLPrefix . 'package.relationships+xml', + 'xml' => 'application/xml', - // Rels - $this->writeDefaultContentType( - $xmlWriter, - 'rels', - 'application/vnd.openxmlformats-package.relationships+xml' ); - - // XML - $this->writeDefaultContentType( - $xmlWriter, - 'xml', - 'application/xml' - ); - - // Add media content-types - foreach ($imageTypes as $key => $value) { - $this->writeDefaultContentType($xmlWriter, $key, $value); + if (is_array($imageTypes)) { + $defaults = array_merge($defaults, $imageTypes); } - - // Add embedding content-types if (count($objectTypes) > 0) { - $this->writeDefaultContentType( - $xmlWriter, - 'bin', - 'application/vnd.openxmlformats-officedocument.oleObject' - ); + $defaults['bin'] = $OpenXMLPrefix . 'officedocument.oleObject'; } - - // DocProps - $this->writeOverrideContentType( - $xmlWriter, - '/docProps/app.xml', - 'application/vnd.openxmlformats-officedocument.extended-properties+xml' + $overrides = array( + '/docProps/core.xml' => $OpenXMLPrefix . 'package.core-properties+xml', + '/docProps/app.xml' => $OpenXMLPrefix . 'officedocument.extended-properties+xml', + '/word/document.xml' => $WordMLPrefix . 'document.main+xml', + '/word/styles.xml' => $WordMLPrefix . 'styles+xml', + '/word/numbering.xml' => $WordMLPrefix . 'numbering+xml', + '/word/settings.xml' => $WordMLPrefix . 'settings+xml', + '/word/theme/theme1.xml' => $OpenXMLPrefix . 'officedocument.theme+xml', + '/word/webSettings.xml' => $WordMLPrefix . 'webSettings+xml', + '/word/fontTable.xml' => $WordMLPrefix . 'fontTable+xml', + '/word/footnotes.xml' => $WordMLPrefix . 'footnotes+xml', ); - - $this->writeOverrideContentType( - $xmlWriter, - '/docProps/core.xml', - 'application/vnd.openxmlformats-package.core-properties+xml' - ); - - // Document - $this->writeOverrideContentType( - $xmlWriter, - '/word/document.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' - ); - - // Styles - $this->writeOverrideContentType( - $xmlWriter, - '/word/styles.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml' - ); - - // Numbering - $this->writeOverrideContentType( - $xmlWriter, - '/word/numbering.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml' - ); - - // Settings - $this->writeOverrideContentType( - $xmlWriter, - '/word/settings.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml' - ); - - // Theme1 - $this->writeOverrideContentType( - $xmlWriter, - '/word/theme/theme1.xml', - 'application/vnd.openxmlformats-officedocument.theme+xml' - ); - - // WebSettings - $this->writeOverrideContentType( - $xmlWriter, - '/word/webSettings.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml' - ); - - // Font Table - $this->writeOverrideContentType( - $xmlWriter, - '/word/fontTable.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml' - ); - - // Footnotes - $this->writeOverrideContentType( - $xmlWriter, - '/word/footnotes.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml' - ); - for ($i = 1; $i <= $cHdrs; $i++) { - $this->writeOverrideContentType( - $xmlWriter, - '/word/header' . $i . '.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml' - ); + $overrides["/word/header{$i}.xml"] = $WordMLPrefix . 'header+xml'; } - for ($i = 1; $i <= count($footers); $i++) { if (!is_null($footers[$i])) { - $this->writeOverrideContentType( - $xmlWriter, - '/word/footer' . $i . '.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml' - ); + $overrides["/word/footer{$i}.xml"] = $WordMLPrefix . 'footer+xml'; } } + $xmlWriter = $this->getXmlWriter(); + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('Types'); + $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); + foreach ($defaults as $key => $value) + { + $this->writeContentType($xmlWriter, true, $key, $value); + } + foreach ($overrides as $key => $value) + { + $this->writeContentType($xmlWriter, false, $key, $value); + } $xmlWriter->endElement(); - // Return return $xmlWriter->getData(); } /** - * Write Default XML element + * Write content types element * - * @param XMLWriter $xmlWriter XML Writer - * @param string $pPartname Part name - * @param string $pContentType Content type + * @param XMLWriter $xmlWriter XML Writer + * @param boolean $isDefault + * @param string $partName Part name + * @param string $contentType Content type * @throws Exception */ - private function writeDefaultContentType(XMLWriter $xmlWriter, $pPartname = '', $pContentType = '') + private function writeContentType(XMLWriter $xmlWriter, $isDefault, $partName = '', $contentType = '') { - if ($pPartname != '' && $pContentType != '') { - // Write content type - $xmlWriter->startElement('Default'); - $xmlWriter->writeAttribute('Extension', $pPartname); - $xmlWriter->writeAttribute('ContentType', $pContentType); - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } - - /** - * Write Override XML element - * - * @param XMLWriter $xmlWriter - * @param string $pPartname Part name - * @param string $pContentType Content type - * @throws Exception - */ - private function writeOverrideContentType(XMLWriter $xmlWriter, $pPartname = '', $pContentType = '') - { - if ($pPartname != '' && $pContentType != '') { - // Write content type - $xmlWriter->startElement('Override'); - $xmlWriter->writeAttribute('PartName', $pPartname); - $xmlWriter->writeAttribute('ContentType', $pContentType); + if ($partName != '' && $contentType != '') { + $element = $isDefault ? 'Default' : 'Override'; + $partAttribute = $isDefault ? 'Extension' : 'PartName'; + $xmlWriter->startElement($element); + $xmlWriter->writeAttribute($partAttribute, $partName); + $xmlWriter->writeAttribute('ContentType', $contentType); $xmlWriter->endElement(); } else { throw new Exception("Invalid parameters passed."); @@ -215,4 +118,32 @@ class ContentTypes extends WriterPart throw new Exception("File $pFile does not exist"); } } + + /** + * Write Default XML element + * + * @param XMLWriter $xmlWriter + * @param string $partName Part name + * @param string $contentType Content type + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + private function writeDefaultContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '') + { + $this->writeContentType($xmlWriter, true, $partName, $contentType); + } + + /** + * Write Override XML element + * + * @param XMLWriter $xmlWriter + * @param string $partName Part name + * @param string $contentType Content type + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + private function writeOverrideContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '') + { + $this->writeContentType($xmlWriter, false, $partName, $contentType); + } } diff --git a/tests/PhpWord/Tests/Element/ObjectTest.php b/tests/PhpWord/Tests/Element/ObjectTest.php index 22b4787f..0f5f191a 100644 --- a/tests/PhpWord/Tests/Element/ObjectTest.php +++ b/tests/PhpWord/Tests/Element/ObjectTest.php @@ -83,17 +83,4 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $oObject->setImageRelationId($iVal); $this->assertEquals($oObject->getImageRelationId(), $iVal); } - - /** - * Set/get object relation Id - */ - public function testObjectId() - { - $src = __DIR__ . "/../_files/documents/sheet.xls"; - $oObject = new Object($src); - - $iVal = rand(1, 1000); - $oObject->setObjectId($iVal); - $this->assertEquals($oObject->getObjectId(), $iVal); - } } From dd9faaee06f0500deb1b175984c81ba37691a6e3 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 5 Apr 2014 00:57:50 +0700 Subject: [PATCH 056/146] Add Media::reset(), Style::reset(), Footnote::reset(), and TOC::reset() --- CHANGELOG.md | 4 + src/PhpWord/Footnote.php | 8 ++ src/PhpWord/Media.php | 8 ++ src/PhpWord/Settings.php | 12 +-- src/PhpWord/Style.php | 86 +++++++++----------- src/PhpWord/TOC.php | 40 +++++---- tests/PhpWord/Tests/Container/HeaderTest.php | 11 +++ tests/PhpWord/Tests/FootnoteTest.php | 3 + tests/PhpWord/Tests/MediaTest.php | 5 +- tests/PhpWord/Tests/StyleTest.php | 4 + tests/PhpWord/Tests/TOCTest.php | 4 + 11 files changed, 114 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80a6253a..fea9e22c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 - Link: Ability to add link in header/footer - @ivanlanin GH-187 - Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 +- Media: Add `Media::reset()` to reset all media data - @juzi GH-19 +- Style: Add `Style::reset()` to reset all styles +- Footnote: Add `Footnote::reset()` to reset all footnotes +- TOC: Add `TOC::reset()` to reset all TOC ### Bugfixes diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index f656dc3a..1c11bbff 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -59,6 +59,14 @@ class Footnote return count(self::$elements); } + /** + * Reset footer elements + */ + public static function reset() + { + self::$elements = array(); + } + /** * Add new Footnote Link Element * diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index d354e399..63c88361 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -145,6 +145,14 @@ class Media return $mediaElements; } + /** + * Reset media elements + */ + public static function reset() + { + self::$media = array(); + } + /** * Add new Section Media Element * diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 0fb8bad0..0af6cf72 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -23,7 +23,7 @@ class Settings * * @var boolean */ - private static $_xmlWriterCompatibility = true; + private static $xmlWriterCompatibility = true; /** * Name of the class used for Zip file management @@ -32,7 +32,7 @@ class Settings * * @var string */ - private static $_zipClass = self::ZIPARCHIVE; + private static $zipClass = self::ZIPARCHIVE; /** * Set the compatibility option used by the XMLWriter @@ -43,7 +43,7 @@ class Settings public static function setCompatibility($compatibility) { if (is_bool($compatibility)) { - self::$_xmlWriterCompatibility = $compatibility; + self::$xmlWriterCompatibility = $compatibility; return true; } return false; @@ -56,7 +56,7 @@ class Settings */ public static function getCompatibility() { - return self::$_xmlWriterCompatibility; + return self::$xmlWriterCompatibility; } /** @@ -70,7 +70,7 @@ class Settings { if (($zipClass === self::PCLZIP) || ($zipClass === self::ZIPARCHIVE)) { - self::$_zipClass = $zipClass; + self::$zipClass = $zipClass; return true; } return false; @@ -86,6 +86,6 @@ class Settings */ public static function getZipClass() { - return self::$_zipClass; + return self::$zipClass; } // function getZipClass() } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index f7b8e4c6..3db67cb5 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -23,7 +23,7 @@ class Style * * @var array */ - private static $_styleElements = array(); + private static $styles = array(); /** * Add paragraph style @@ -33,17 +33,7 @@ class Style */ public static function addParagraphStyle($styleName, $styles) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $style = new Paragraph(); - foreach ($styles as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $style->setStyleValue($key, $value); - } - - self::$_styleElements[$styleName] = $style; - } + self::setStyleValues($styleName, $styles, new Paragraph()); } /** @@ -55,16 +45,7 @@ class Style */ public static function addFontStyle($styleName, $styleFont, $styleParagraph = null) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $font = new Font('text', $styleParagraph); - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $font->setStyleValue($key, $value); - } - self::$_styleElements[$styleName] = $font; - } + self::setStyleValues($styleName, $styleFont, new Font('text', $styleParagraph)); } /** @@ -75,17 +56,7 @@ class Style */ public static function addLinkStyle($styleName, $styles) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $style = new Font('link'); - foreach ($styles as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $style->setStyleValue($key, $value); - } - - self::$_styleElements[$styleName] = $style; - } + self::setStyleValues($styleName, $styles, new Font('link')); } /** @@ -97,10 +68,10 @@ class Style */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - if (!array_key_exists($styleName, self::$_styleElements)) { + if (!array_key_exists($styleName, self::$styles)) { $style = new Table($styleTable, $styleFirstRow); - self::$_styleElements[$styleName] = $style; + self::$styles[$styleName] = $style; } } @@ -114,17 +85,15 @@ class Style public static function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) { $styleName = 'Heading_' . $titleCount; - if (!array_key_exists($styleName, self::$_styleElements)) { - $font = new Font('title', $styleParagraph); - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $font->setStyleValue($key, $value); - } + self::setStyleValues("Heading_{$titleCount}", $styleFont, new Font('title', $styleParagraph)); + } - self::$_styleElements[$styleName] = $font; - } + /** + * Reset styles + */ + public static function reset() + { + self::$styles = array(); } /** @@ -144,7 +113,7 @@ class Style */ public static function getStyles() { - return self::$_styleElements; + return self::$styles; } /** @@ -154,10 +123,31 @@ class Style */ public static function getStyle($styleName) { - if (array_key_exists($styleName, self::$_styleElements)) { - return self::$_styleElements[$styleName]; + if (array_key_exists($styleName, self::$styles)) { + return self::$styles[$styleName]; } else { return null; } } + + /** + * Set style values + * + * @param string $styleName + * @param array $styleValues + * @param mixed $styleObject + */ + private static function setStyleValues($styleName, $styleValues, $styleObject) + { + if (!array_key_exists($styleName, self::$styles)) { + foreach ($styleValues as $key => $value) { + if (substr($key, 0, 1) != '_') { + $key = '_' . $key; + } + $styleObject->setStyleValue($key, $value); + } + + self::$styles[$styleName] = $styleObject; + } + } } diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index bd1c3f38..0dc7c874 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -22,35 +22,35 @@ class TOC * * @var array */ - private static $_titles = array(); + private static $titles = array(); /** * TOC style * * @var TOCStyle */ - private static $_styleTOC; + private static $TOCStyle; /** * Font style * * @var Font|array|string */ - private static $_styleFont; + private static $fontStyle; /** * Title anchor * * @var int */ - private static $_anchor = 252634154; + private static $anchor = 252634154; /** * Title bookmark * * @var int */ - private static $_bookmarkId = 0; + private static $bookmarkId = 0; /** @@ -61,28 +61,28 @@ class TOC */ public function __construct($styleFont = null, $styleTOC = null) { - self::$_styleTOC = new TOCStyle(); + self::$TOCStyle = new TOCStyle(); if (!is_null($styleTOC) && is_array($styleTOC)) { foreach ($styleTOC as $key => $value) { if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - self::$_styleTOC->setStyleValue($key, $value); + self::$TOCStyle->setStyleValue($key, $value); } } if (!is_null($styleFont)) { if (is_array($styleFont)) { - self::$_styleFont = new Font(); + self::$fontStyle = new Font(); foreach ($styleFont as $key => $value) { if (substr($key, 0, 1) != '_') { $key = '_' . $key; } - self::$_styleFont->setStyleValue($key, $value); + self::$fontStyle->setStyleValue($key, $value); } } else { - self::$_styleFont = $styleFont; + self::$fontStyle = $styleFont; } } } @@ -96,8 +96,8 @@ class TOC */ public static function addTitle($text, $depth = 0) { - $anchor = '_Toc' . ++self::$_anchor; - $bookmarkId = self::$_bookmarkId++; + $anchor = '_Toc' . ++self::$anchor; + $bookmarkId = self::$bookmarkId++; $title = array(); $title['text'] = $text; @@ -105,7 +105,7 @@ class TOC $title['anchor'] = $anchor; $title['bookmarkId'] = $bookmarkId; - self::$_titles[] = $title; + self::$titles[] = $title; return array($anchor, $bookmarkId); } @@ -117,7 +117,15 @@ class TOC */ public static function getTitles() { - return self::$_titles; + return self::$titles; + } + + /** + * Reset footnotes + */ + public static function reset() + { + self::$titles = array(); } /** @@ -127,7 +135,7 @@ class TOC */ public static function getStyleTOC() { - return self::$_styleTOC; + return self::$TOCStyle; } /** @@ -137,6 +145,6 @@ class TOC */ public static function getStyleFont() { - return self::$_styleFont; + return self::$fontStyle; } } diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php index d7425bdc..9d13d57c 100644 --- a/tests/PhpWord/Tests/Container/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -220,4 +220,15 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::EVEN); } + + /** + * Add footnote exception + * + * @expectedException BadMethodCallException + */ + public function testAddFootnoteException() + { + $header = new Header(1); + $header->addFootnote(); + } } diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index 955d02e5..47aea9a3 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -31,5 +31,8 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, $rIdLink); $this->assertEquals(1, count(Footnote::getFootnoteElements())); $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); + + Footnote::reset(); + $this->assertEquals(0, count(Footnote::getFootnoteElements())); } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index b1a49059..3df52e4a 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -83,7 +83,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase } /** - * Add footer media element + * Add footer media element and reset media */ public function testAddFooterMediaElement() { @@ -94,5 +94,8 @@ class MediaTest extends \PHPUnit_Framework_TestCase Media::addMediaElement('footer1', 'image', $remote, new Image($remote)); $this->assertEquals(2, Media::countMediaElements('footer1')); + + Media::reset(); + $this->assertEquals(0, Media::countMediaElements('footer1')); } } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index 6381cbc9..b323ece4 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -43,6 +43,10 @@ class StyleTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name)); } $this->assertNull(Style::getStyle('Unknown')); + + Style::reset(); + $this->assertEquals(0, count(Style::getStyles())); + } /** diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 100206a4..0a060eb8 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -78,5 +78,9 @@ class TOCTest extends \PHPUnit_Framework_TestCase $this->assertEquals($depth, $savedTitles[$i]['depth']); $i++; } + + TOC::reset(); + $this->assertEquals(0, count(TOC::getTitles())); + } } From 6aa73544a618b7bfd17148be096e4b8b1eedd370 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 5 Apr 2014 01:41:48 +0700 Subject: [PATCH 057/146] Fix failed test --- src/PhpWord/Shared/ZipArchive.php | 2 ++ src/PhpWord/Writer/ODText/Content.php | 4 ++++ src/PhpWord/Writer/ODText/Meta.php | 4 ++++ src/PhpWord/Writer/ODText/Styles.php | 4 ++++ src/PhpWord/Writer/Word2007/ContentTypes.php | 6 ++---- src/PhpWord/Writer/Word2007/DocProps.php | 4 ++++ src/PhpWord/Writer/Word2007/Document.php | 4 ++++ 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 7ef0889e..46d5c036 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -170,6 +170,8 @@ class ZipArchive $list = $this->zip->listContent(); $listCount = count($list); $listIndex = -1; + $contents = null; + for ($i = 0; $i < $listCount; ++$i) { if (strtolower($list[$i]["filename"]) == strtolower($fileName) || strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 0669bc41..7fc0d2df 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -39,6 +39,10 @@ class Content extends WriterPart */ public function writeContent(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index d0d593e2..fc5314e9 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -24,6 +24,10 @@ class Meta extends WriterPart */ public function writeMeta(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index fa81ea9e..8839f568 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -28,6 +28,10 @@ class Styles extends WriterPart */ public function writeStyles(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 9e6853d0..9a383e9b 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -66,12 +66,10 @@ class ContentTypes extends WriterPart $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Types'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); - foreach ($defaults as $key => $value) - { + foreach ($defaults as $key => $value) { $this->writeContentType($xmlWriter, true, $key, $value); } - foreach ($overrides as $key => $value) - { + foreach ($overrides as $key => $value) { $this->writeContentType($xmlWriter, false, $key, $value); } $xmlWriter->endElement(); diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index ceb5db04..cfa238e5 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -21,6 +21,10 @@ class DocProps extends WriterPart */ public function writeDocPropsApp(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 8bf46a0b..499aad19 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -28,6 +28,10 @@ class Document extends Base */ public function writeDocument(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); From 03934af33416fd940bac84f80757a8fe621a8143 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 5 Apr 2014 19:02:49 +0700 Subject: [PATCH 058/146] Refactor header/footer and media model --- CHANGELOG.md | 4 +- src/PhpWord/Container/Container.php | 28 ++- src/PhpWord/Container/Footer.php | 42 +++- src/PhpWord/Container/Header.php | 47 ++++- src/PhpWord/Container/Section.php | 92 ++++++--- src/PhpWord/Element/Element.php | 4 + src/PhpWord/Element/TextRun.php | 2 - src/PhpWord/Footnote.php | 4 +- src/PhpWord/Media.php | 75 +++---- src/PhpWord/Writer/ODText/Manifest.php | 18 -- src/PhpWord/Writer/Word2007.php | 188 +++++++----------- src/PhpWord/Writer/Word2007/ContentTypes.php | 110 +++------- src/PhpWord/Writer/Word2007/Document.php | 16 +- src/PhpWord/Writer/Word2007/Rels.php | 22 +- src/PhpWord/Writer/Word2007/Styles.php | 4 + tests/PhpWord/Tests/Container/SectionTest.php | 4 +- tests/PhpWord/Tests/MediaTest.php | 57 +++--- 17 files changed, 356 insertions(+), 361 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fea9e22c..548ef026 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,8 +39,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - `createSection` replaced by `addSection` - `Element\Footnote::getReferenceId` replaced by `Container\Container::getRelationId` - `Element\Footnote::setReferenceId` replaced by `Container\Container::setRelationId` -- `Footnote::addFootnoteLinkElement` replaced by `Media::addMediaElement` -- `Footnote::getFootnoteLinkElements` replaced by `Media::getMediaElements` +- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement` +- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements` - All current methods on `Media` ### Miscellaneous diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Container/Container.php index ec66a5a0..2584a1f7 100644 --- a/src/PhpWord/Container/Container.php +++ b/src/PhpWord/Container/Container.php @@ -49,7 +49,7 @@ abstract class Container extends Element * * @var int */ - protected $containerId; + protected $sectionId; /** * Elements collection @@ -123,7 +123,7 @@ abstract class Container extends Element $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); $link->setDocPart($this->getDocPart(), $this->getDocPartId()); - $rID = Media::addMediaElement($elementDocPart, 'link', $linkSrc); + $rID = Media::addElement($elementDocPart, 'link', $linkSrc); $link->setRelationId($rID); $this->elements[] = $link; @@ -250,14 +250,10 @@ abstract class Container extends Element $image = new Image($src, $style, $isWatermark); $image->setDocPart($this->getDocPart(), $this->getDocPartId()); - if (!is_null($image->getSource())) { - $rID = Media::addMediaElement($elementDocPart, 'image', $src, $image); - $image->setRelationId($rID); - $this->elements[] = $image; - return $image; - } else { - throw new InvalidImageException; - } + $rID = Media::addElement($elementDocPart, 'image', $src, $image); + $image->setRelationId($rID); + $this->elements[] = $image; + return $image; } /** @@ -284,9 +280,9 @@ abstract class Container extends Element $ext = substr($ext, 0, -1); } $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); - $rID = Media::addMediaElement($elementDocPart, 'object', $src); + $rID = Media::addElement($elementDocPart, 'object', $src); $object->setRelationId($rID); - $rIDimg = Media::addMediaElement($elementDocPart, 'image', $icon, new Image($icon)); + $rIDimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); $object->setImageRelationId($rIDimg); $this->elements[] = $object; return $object; @@ -307,7 +303,7 @@ abstract class Container extends Element $footnote = new FootnoteElement($paragraphStyle); $refID = FootnoteCollection::addFootnoteElement($footnote); - $footnote->setDocPart($this->getDocPart(), $this->getDocPartId()); + $footnote->setDocPart('footnote', $this->getDocPartId()); $footnote->setRelationId($refID); $this->elements[] = $footnote; @@ -337,11 +333,11 @@ abstract class Container extends Element /** * Get section number * - * @return array + * @return integer */ public function getSectionId() { - return $this->containerId; + return $this->sectionId; } /** @@ -474,7 +470,7 @@ abstract class Container extends Element { $isCellTextrun = in_array($this->container, array('cell', 'textrun')); $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; - $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->containerId; + $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId; $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); return $inHeaderFooter ? $docPart . $docPartId : $docPart; diff --git a/src/PhpWord/Container/Footer.php b/src/PhpWord/Container/Footer.php index 440b3b4e..47287c8b 100755 --- a/src/PhpWord/Container/Footer.php +++ b/src/PhpWord/Container/Footer.php @@ -14,15 +14,51 @@ namespace PhpOffice\PhpWord\Container; */ class Footer extends Container { + const AUTO = 'default'; // default and odd pages + const FIRST = 'first'; + const EVEN = 'even'; + + /** + * Header type + * + * @var string + */ + private $type = self::AUTO; + /** * Create new instance * * @param int $sectionId + * @param int $footerId + * @param string $type */ - public function __construct($sectionId) + public function __construct($sectionId, $footerId = 1, $type = self::AUTO) { $this->container = 'footer'; - $this->containerId = $sectionId; - $this->setDocPart($this->container, $this->containerId); + $this->sectionId = $sectionId; + $this->setType($type); + $this->setDocPart($this->container, ($sectionId - 1) * 3 + $footerId); + } + + /** + * Set type + * + * @param string $value + * @since 0.9.2 + */ + public function setType($value = self::AUTO) + { + $this->type = $value; + } + + /** + * Get type + * + * @return string + * @since 0.9.2 + */ + public function getType() + { + return $this->type; } } diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Container/Header.php index 39c6ca98..2920e3cf 100755 --- a/src/PhpWord/Container/Header.php +++ b/src/PhpWord/Container/Header.php @@ -20,29 +20,32 @@ class Header extends Container * Header types constants * * @var string - * @link http://www.schemacentral.com/sc/ooxml/a-wheaderType-4.html Header or Footer Type + * @link http://www.schemacentral.com/sc/ooxml/a-wtype-4.html Header or Footer Type */ - const AUTO = 'default'; // Did not use DEFAULT because it is a PHP keyword - const EVEN = 'even'; + const AUTO = 'default'; // default and odd pages const FIRST = 'first'; + const EVEN = 'even'; /** * Header type * * @var string */ - private $headerType = self::AUTO; + private $type = self::AUTO; /** * Create new instance * * @param int $sectionId + * @param int $headerId + * @param string $type */ - public function __construct($sectionId) + public function __construct($sectionId, $headerId = 1, $type = self::AUTO) { $this->container = 'header'; - $this->containerId = $sectionId; - $this->setDocPart($this->container, $this->containerId); + $this->sectionId = $sectionId; + $this->setType($type); + $this->setDocPart($this->container, ($sectionId - 1) * 3 + $headerId); } /** @@ -57,35 +60,57 @@ class Header extends Container return $this->addImage($src, $style, true); } + /** + * Set header type + * + * @param string $value + * @since 0.9.2 + */ + public function setType($value = self::AUTO) + { + if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) { + $value = self::AUTO; + } + $this->type = $value; + } + /** * Get header type + * + * @return string */ public function getType() { - return $this->headerType; + return $this->type; } /** * Reset type to default + * + * @return string */ public function resetType() { - return $this->headerType = self::AUTO; + return $this->type = self::AUTO; } /** * First page only header + * + * @return string */ public function firstPage() { - return $this->headerType = self::FIRST; + return $this->type = self::FIRST; } /** * Even numbered pages only + * + * @return string */ public function evenPage() { - return $this->headerType = self::EVEN; + return $this->type = self::EVEN; } } diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index 69edec41..46f2d44e 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Container; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\TOC; use PhpOffice\PhpWord\Container\Footer; use PhpOffice\PhpWord\Container\Header; @@ -28,19 +29,18 @@ class Section extends Container private $settings; /** - * Section headers + * Section headers, indexed from 1, not zero * * @var Header[] */ private $headers = array(); /** - * Section footer + * Section footers, indexed from 1, not zero * - * @var Footer + * @var Footer[] */ - private $footer = null; - + private $footers = array(); /** * Create new instance @@ -51,8 +51,8 @@ class Section extends Container public function __construct($sectionCount, $settings = null) { $this->container = 'section'; - $this->containerId = $sectionCount; - $this->setDocPart($this->container, $this->containerId); + $this->sectionId = $sectionCount; + $this->setDocPart($this->container, $this->sectionId); $this->settings = new Settings(); $this->setSettings($settings); } @@ -109,29 +109,29 @@ class Section extends Container /** * Add header * + * @param string $type * @return Header + * @since 0.9.2 */ - public function addHeader() + public function addHeader($type = Header::AUTO) { - $header = new Header($this->containerId); - $this->headers[] = $header; - return $header; + return $this->addHeaderFooter($type, true); } /** * Add footer * + * @param string $type * @return Footer + * @since 0.9.2 */ - public function addFooter() + public function addFooter($type = Header::AUTO) { - $footer = new Footer($this->containerId); - $this->footer = $footer; - return $footer; + return $this->addHeaderFooter($type, false); } /** - * Get Headers + * Get header elements * * @return Header[] */ @@ -141,13 +141,13 @@ class Section extends Container } /** - * Get footer element + * Get footer elements * - * @return Footer + * @return Footer[] */ - public function getFooter() + public function getFooters() { - return $this->footer; + return $this->footers; } /** @@ -160,10 +160,38 @@ class Section extends Container */ public function hasDifferentFirstPage() { - $value = array_filter($this->headers, function (Header &$header) { - return $header->getType() == Header::FIRST; - }); - return count($value) > 0; + foreach ($this->headers as $header) { + if ($header->getType() == Header::FIRST) { + return true; + } + } + return false; + } + + /** + * Add header/footer + * + * @param string $type + * @param string $header + * @return Header|Footer + * @since 0.9.2 + */ + private function addHeaderFooter($type = Header::AUTO, $header = true) + { + $collectionArray = $header ? 'headers' : 'footers'; + $containerClass = 'PhpOffice\\PhpWord\\Container\\'; + $containerClass .= ($header ? 'Header' : 'Footer'); + $collection = &$this->$collectionArray; + + if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { + $index = count($collection); + $container = new $containerClass($this->sectionId, ++$index, $type); + $collection[$index] = $container; + return $container; + } else { + throw new Exception('Invalid header/footer type.'); + } + } /** @@ -189,4 +217,20 @@ class Section extends Container { return $this->addFooter(); } + + /** + * Get footer + * + * @return Footer + * @deprecated 0.9.2 + * @codeCoverageIgnore + */ + public function getFooter() + { + if (empty($this->footers)) { + return null; + } else { + return $this->footers[1]; + } + } } diff --git a/src/PhpWord/Element/Element.php b/src/PhpWord/Element/Element.php index b3565775..ec0dbc5c 100644 --- a/src/PhpWord/Element/Element.php +++ b/src/PhpWord/Element/Element.php @@ -30,6 +30,10 @@ abstract class Element /** * Document part Id * + * For header and footer, this will be = ($sectionId - 1) * 3 + $index + * because the max number of header/footer in every page is 3, i.e. + * AUTO, FIRST, and EVEN (AUTO = ODD) + * * @var integer */ private $docPartId = 1; diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 794ad230..6be08fc4 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -28,8 +28,6 @@ class TextRun extends Container * Create new instance * * @param string|array|Paragraph $paragraphStyle - * @param string $docPart section|header|footer - * @param int $docPartId */ public function __construct($paragraphStyle = null) { diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 1c11bbff..9b11518b 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -77,7 +77,7 @@ class Footnote */ public static function addFootnoteLinkElement($linkSrc) { - return Media::addMediaElement('footnotes', 'hyperlink', $linkSrc); + return Media::addElement('footnotes', 'link', $linkSrc); } /** @@ -89,6 +89,6 @@ class Footnote */ public static function getFootnoteLinkElements() { - return Media::getMediaElements('footnotes', 'hyperlink'); + return Media::getElements('footnotes', 'link'); } } diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 63c88361..921fc154 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Element\Image; /** @@ -21,7 +22,7 @@ class Media * * @var array */ - private static $media = array(); + private static $elements = array(); /** * Add new media element @@ -31,19 +32,20 @@ class Media * @param string $source * @param Image $image * @return integer + * @since 0.9.2 */ - public static function addMediaElement($container, $mediaType, $source, Image $image = null) + public static function addElement($container, $mediaType, $source, Image $image = null) { // Assign unique media Id and initiate media container if none exists $mediaId = md5($container . $source); - if (!array_key_exists($container, self::$media)) { - self::$media[$container]= array(); + if (!array_key_exists($container, self::$elements)) { + self::$elements[$container]= array(); } // Add media if not exists or point to existing media - if (!array_key_exists($mediaId, self::$media[$container])) { - $mediaCount = self::countMediaElements($container); - $mediaTypeCount = self::countMediaElements($container, $mediaType); + if (!array_key_exists($mediaId, self::$elements[$container])) { + $mediaCount = self::countElements($container); + $mediaTypeCount = self::countElements($container, $mediaType); $mediaData = array(); $relId = ++$mediaCount; $target = null; @@ -51,16 +53,17 @@ class Media // Images if ($mediaType == 'image') { - $isMemImage = false; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $ext = $image->getImageExtension(); - $ext = strtolower($ext); + if (is_null($image)) { + throw new Exception('Image object not assigned.'); } + $isMemImage = $image->getIsMemImage(); + $ext = $image->getImageExtension(); + $mediaData['imageExtension'] = $ext; + $mediaData['imageType'] = $image->getImageType(); if ($isMemImage) { $mediaData['isMemImage'] = true; - $mediaData['createfunction'] = $image->getImageCreateFunction(); - $mediaData['imagefunction'] = $image->getImageFunction(); + $mediaData['createFunction'] = $image->getImageCreateFunction(); + $mediaData['imageFunction'] = $image->getImageFunction(); } $target = "media/{$container}_image{$mediaTypeCount}.{$ext}"; // Objects @@ -76,10 +79,10 @@ class Media $mediaData['target'] = $target; $mediaData['type'] = $mediaType; $mediaData['rID'] = $relId; - self::$media[$container][$mediaId] = $mediaData; + self::$elements[$container][$mediaId] = $mediaData; return $relId; } else { - return self::$media[$container][$mediaId]['rID']; + return self::$elements[$container][$mediaId]['rID']; } } @@ -89,13 +92,14 @@ class Media * @param string $container section|headerx|footerx|footnote * @param string $mediaType image|object|link * @return integer + * @since 0.9.2 */ - public static function countMediaElements($container, $mediaType = null) + public static function countElements($container, $mediaType = null) { $mediaCount = 0; - if (array_key_exists($container, self::$media)) { - foreach (self::$media[$container] as $mediaKey => $mediaData) { + if (array_key_exists($container, self::$elements)) { + foreach (self::$elements[$container] as $mediaKey => $mediaData) { if (!is_null($mediaType)) { if ($mediaType == $mediaData['type']) { $mediaCount++; @@ -115,23 +119,24 @@ class Media * @param string $container section|headerx|footerx|footnote * @param string $mediaType image|object|link * @return array + * @since 0.9.2 */ - public static function getMediaElements($container, $mediaType = null) + public static function getElements($container, $mediaType = null) { $mediaElements = array(); // If header/footer, search for headerx and footerx where x is number if ($container == 'header' || $container == 'footer') { - foreach (self::$media as $key => $val) { + foreach (self::$elements as $key => $val) { if (substr($key, 0, 6) == $container) { $mediaElements[$key] = $val; } } } else { - if (!array_key_exists($container, self::$media)) { + if (!array_key_exists($container, self::$elements)) { return $mediaElements; } - foreach (self::$media[$container] as $mediaKey => $mediaData) { + foreach (self::$elements[$container] as $mediaKey => $mediaData) { if (!is_null($mediaType)) { if ($mediaType == $mediaData['type']) { $mediaElements[$mediaKey] = $mediaData; @@ -150,7 +155,7 @@ class Media */ public static function reset() { - self::$media = array(); + self::$elements = array(); } /** @@ -159,13 +164,13 @@ class Media * @param string $src * @param string $type * @param Image $image - * @return integer|array + * @return integer * @deprecated 0.9.2 * @codeCoverageIgnore */ public static function addSectionMediaElement($src, $type, Image $image = null) { - return self::addMediaElement("section", $type, $src, $image); + return self::addElement('section', $type, $src, $image); } /** @@ -178,7 +183,7 @@ class Media */ public static function addSectionLinkElement($linkSrc) { - return self::addMediaElement('section', 'link', $linkSrc); + return self::addElement('section', 'link', $linkSrc); } /** @@ -191,7 +196,7 @@ class Media */ public static function getSectionMediaElements($key = null) { - return self::getMediaElements('section', $key); + return self::getElements('section', $key); } /** @@ -204,7 +209,7 @@ class Media */ public static function countSectionMediaElements($key = null) { - return self::countMediaElements('section', $key); + return self::countElements('section', $key); } /** @@ -219,7 +224,7 @@ class Media */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) { - return self::addMediaElement("header{$headerCount}", 'image', $src, $image); + return self::addElement("header{$headerCount}", 'image', $src, $image); } /** @@ -232,7 +237,7 @@ class Media */ public static function countHeaderMediaElements($key) { - return self::countMediaElements($key); + return self::countElements($key); } /** @@ -244,7 +249,7 @@ class Media */ public static function getHeaderMediaElements() { - return self::getMediaElements('header'); + return self::getElements('header'); } /** @@ -259,7 +264,7 @@ class Media */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) { - return self::addMediaElement("footer{$footerCount}", 'image', $src, $image); + return self::addElement("footer{$footerCount}", 'image', $src, $image); } /** @@ -272,7 +277,7 @@ class Media */ public static function countFooterMediaElements($key) { - return self::countMediaElements($key); + return self::countElements($key); } /** @@ -284,6 +289,6 @@ class Media */ public static function getFooterMediaElements() { - return self::getMediaElements('footer'); + return self::getElements('footer'); } } diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 3712cf66..ecda1918 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -63,22 +63,4 @@ class Manifest extends WriterPart // Return return $xmlWriter->getData(); } - - - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws Exception - */ - private function getImageMimeType($pFile = '') - { - if (file_exists($pFile)) { - $image = getimagesize($pFile); - return image_type_to_mime_type($image[2]); - } else { - throw new Exception("File $pFile does not exist"); - } - } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 084deb8d..ba887f01 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -29,18 +29,18 @@ use PhpOffice\PhpWord\Writer\Word2007\Styles; class Word2007 extends Writer implements IWriter { /** - * Types of images + * Content types values * * @var array */ - private $imageTypes = array(); + private $cTypes = array('default' => array(), 'override' => array()); /** - * Types of objects + * Document relationship * * @var array */ - private $objectTypes = array(); + private $docRels = array(); /** * Create new Word2007 writer @@ -98,14 +98,18 @@ class Word2007 extends Writer implements IWriter } } - // Add section media files - $sectionElements = array(); + // Content types + $this->cTypes['default'] = array( + 'rels' => 'application/vnd.openxmlformats-package.relationships+xml', + 'xml' => 'application/xml', + ); - $secElements = Media::getMediaElements('section'); - if (!empty($secElements)) { - $this->addFilesToPackage($objZip, $secElements); - foreach ($secElements as $element) { - $sectionElements[] = $element; + // Add section media files + $sectionMedia = Media::getElements('section'); + if (!empty($sectionMedia)) { + $this->addFilesToPackage($objZip, $sectionMedia); + foreach ($sectionMedia as $element) { + $this->docRels[] = $element; } } @@ -114,70 +118,32 @@ class Word2007 extends Writer implements IWriter $this->addHeaderFooterMedia($objZip, 'footer'); // Add header/footer contents - $cHdrs = 0; - $cFtrs = 0; - $rID = Media::countMediaElements('section') + 6; // @see Rels::writeDocRels for 6 first elements + $overrides = array(); + $rID = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements $sections = $this->phpWord->getSections(); - $footers = array(); foreach ($sections as $section) { - $headers = $section->getHeaders(); - if (!empty($headers)) { - foreach ($headers as $index => &$header) { - $cHdrs++; - $header->setRelationId(++$rID); - $hdrFile = "header{$cHdrs}.xml"; - $sectionElements[] = array('target' => $hdrFile, 'type' => 'header', 'rID' => $rID); - $objZip->addFromString( - "word/{$hdrFile}", - $this->getWriterPart('header')->writeHeader($header) - ); - } - } - $footer = $section->getFooter(); - $footers[++$cFtrs] = $footer; - if (!is_null($footer)) { - $footer->setRelationId(++$rID); - $footerCount = $footer->getSectionId(); - $ftrFile = "footer{$footerCount}.xml"; - $sectionElements[] = array('target' => $ftrFile, 'type' => 'footer', 'rID' => $rID); - $objZip->addFromString( - "word/{$ftrFile}", - $this->getWriterPart('footer')->writeFooter($footer) - ); - } + $this->addHeaderFooterContent($section, $objZip, 'header', $rID); + $this->addHeaderFooterContent($section, $objZip, 'footer', $rID); } // Add footnotes media files, relations, and contents if (Footnote::countFootnoteElements() > 0) { - $sectionElements[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); - $footnoteMedia = Media::getMediaElements('footnote'); + $footnoteMedia = Media::getElements('footnote'); $this->addFilesToPackage($objZip, $footnoteMedia); if (!empty($footnoteMedia)) { - $objZip->addFromString( - 'word/_rels/footnotes.xml.rels', - $this->getWriterPart('rels')->writeMediaRels($footnoteMedia) - ); + $objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('rels')->writeMediaRels($footnoteMedia)); } - $objZip->addFromString( - 'word/footnotes.xml', - $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements()) - ); + $objZip->addFromString('word/footnotes.xml', $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())); + $this->cTypes['override']["/word/footnotes.xml"] = 'footnotes'; + $this->docRels[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); } // Write dynamic files - $objZip->addFromString( - '[Content_Types].xml', - $this->getWriterPart('contenttypes')->writeContentTypes( - $this->imageTypes, - $this->objectTypes, - $cHdrs, - $footers - ) - ); + $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes($this->cTypes)); $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeMainRels()); $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->phpWord)); $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->phpWord)); - $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($sectionElements)); + $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($this->docRels)); $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord)); $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); @@ -200,54 +166,7 @@ class Word2007 extends Writer implements IWriter } /** - * Check content types - * - * @param string $src - */ - private function checkContentTypes($src) - { - $extension = null; - if (stripos(strrev($src), strrev('.php')) === 0) { - $extension = 'php'; - } else { - if (function_exists('exif_imagetype')) { - $imageType = exif_imagetype($src); - } else { - $tmp = getimagesize($src); - $imageType = $tmp[2]; - } - if ($imageType === \IMAGETYPE_JPEG) { - $extension = 'jpg'; - } elseif ($imageType === \IMAGETYPE_GIF) { - $extension = 'gif'; - } elseif ($imageType === \IMAGETYPE_PNG) { - $extension = 'png'; - } elseif ($imageType === \IMAGETYPE_BMP) { - $extension = 'bmp'; - } elseif ($imageType === \IMAGETYPE_TIFF_II || $imageType === \IMAGETYPE_TIFF_MM) { - $extension = 'tif'; - } - } - - if (isset($extension)) { - $imageData = getimagesize($src); - $imageType = image_type_to_mime_type($imageData[2]); - $imageExtension = str_replace('.', '', image_type_to_extension($imageData[2])); - if ($imageExtension === 'jpeg') { - $imageExtension = 'jpg'; - } - if (!in_array($imageType, $this->imageTypes)) { - $this->imageTypes[$imageExtension] = $imageType; - } - } else { - if (!in_array($extension, $this->objectTypes)) { - $this->objectTypes[] = $extension; - } - } - } - - /** - * Check content types + * Add section files to package * * @param mixed $objZip * @param mixed $elements @@ -255,47 +174,78 @@ class Word2007 extends Writer implements IWriter private function addFilesToPackage($objZip, $elements) { foreach ($elements as $element) { + // Do not add link if ($element['type'] == 'link') { continue; } + // Retrieve remote image if (isset($element['isMemImage']) && $element['isMemImage']) { - $image = call_user_func($element['createfunction'], $element['source']); + $image = call_user_func($element['createFunction'], $element['source']); ob_start(); - call_user_func($element['imagefunction'], $image); + call_user_func($element['imageFunction'], $image); $imageContents = ob_get_contents(); ob_end_clean(); $objZip->addFromString('word/' . $element['target'], $imageContents); imagedestroy($image); - - $this->checkContentTypes($element['source']); } else { $objZip->addFile($element['source'], 'word/' . $element['target']); - $this->checkContentTypes($element['source']); + } + // Register content types + if ($element['type'] == 'image') { + $imageExtension = $element['imageExtension']; + $imageType = $element['imageType']; + if (!array_key_exists($imageExtension, $this->cTypes['default'])) { + $this->cTypes['default'][$imageExtension] = $imageType; + } + } else { + if (!array_key_exists('bin', $this->cTypes['default'])) { + $this->cTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject'; + } } } } /** - * Add header/footer media elements + * Add header/footer media files * * @param mixed $objZip * @param string $docPart */ private function addHeaderFooterMedia($objZip, $docPart) { - $elements = Media::getMediaElements($docPart); + $elements = Media::getElements($docPart); if (!empty($elements)) { foreach ($elements as $file => $media) { if (count($media) > 0) { - $objZip->addFromString( - 'word/_rels/' . $file . '.xml.rels', - $this->getWriterPart('rels')->writeMediaRels($media) - ); if (!empty($media)) { $this->addFilesToPackage($objZip, $media); } + $objZip->addFromString("word/_rels/{$file}.xml.rels", $this->getWriterPart('rels')->writeMediaRels($media)); } } } } + + /** + * Add header/footer content + * + * @param Section $section + * @param string $elmType + * @param integer $rID + */ + private function addHeaderFooterContent(&$section, $objZip, $elmType, &$rID) + { + $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; + $writeFunction = $elmType == 'header' ? 'writeHeader' : 'writeFooter'; + $elmCount = ($section->getSectionId() - 1) * 3; + $elmObjects = $section->$getFunction(); + foreach ($elmObjects as $index => &$elmObject) { + $elmCount++; + $elmObject->setRelationId(++$rID); + $elmFile = "{$elmType}{$elmCount}.xml"; + $objZip->addFromString("word/$elmFile", $this->getWriterPart($elmType)->$writeFunction($elmObject)); + $this->cTypes['override']["/word/$elmFile"] = $elmType; + $this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rID); + } + } } diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 9a383e9b..7b371b07 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -19,28 +19,13 @@ class ContentTypes extends WriterPart { /** * Write [Content_Types].xml - * @param array $imageTypes - * @param array $objectTypes - * @param int $cHdrs - * @param array $footers + * + * @param array $contentTypes */ - public function writeContentTypes($imageTypes, $objectTypes, $cHdrs, $footers) + public function writeContentTypes($contentTypes) { - $OpenXMLPrefix = 'application/vnd.openxmlformats-'; - $WordMLPrefix = $OpenXMLPrefix . 'officedocument.wordprocessingml.'; - - $defaults = array( - 'rels' => $OpenXMLPrefix . 'package.relationships+xml', - 'xml' => 'application/xml', - - ); - if (is_array($imageTypes)) { - $defaults = array_merge($defaults, $imageTypes); - } - if (count($objectTypes) > 0) { - $defaults['bin'] = $OpenXMLPrefix . 'officedocument.oleObject'; - } + $WordMLPrefix = $OpenXMLPrefix . 'officedocument.wordprocessingml.'; $overrides = array( '/docProps/core.xml' => $OpenXMLPrefix . 'package.core-properties+xml', '/docProps/app.xml' => $OpenXMLPrefix . 'officedocument.extended-properties+xml', @@ -51,14 +36,12 @@ class ContentTypes extends WriterPart '/word/theme/theme1.xml' => $OpenXMLPrefix . 'officedocument.theme+xml', '/word/webSettings.xml' => $WordMLPrefix . 'webSettings+xml', '/word/fontTable.xml' => $WordMLPrefix . 'fontTable+xml', - '/word/footnotes.xml' => $WordMLPrefix . 'footnotes+xml', ); - for ($i = 1; $i <= $cHdrs; $i++) { - $overrides["/word/header{$i}.xml"] = $WordMLPrefix . 'header+xml'; - } - for ($i = 1; $i <= count($footers); $i++) { - if (!is_null($footers[$i])) { - $overrides["/word/footer{$i}.xml"] = $WordMLPrefix . 'footer+xml'; + + $defaults = $contentTypes['default']; + if (!empty($contentTypes['override'])) { + foreach ($contentTypes['override'] as $key => $val) { + $overrides[$key] = $WordMLPrefix . $val . '+xml'; } } @@ -66,12 +49,8 @@ class ContentTypes extends WriterPart $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Types'); $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); - foreach ($defaults as $key => $value) { - $this->writeContentType($xmlWriter, true, $key, $value); - } - foreach ($overrides as $key => $value) { - $this->writeContentType($xmlWriter, false, $key, $value); - } + $this->writeContentType($xmlWriter, $defaults, true); + $this->writeContentType($xmlWriter, $overrides, false); $xmlWriter->endElement(); return $xmlWriter->getData(); @@ -86,62 +65,19 @@ class ContentTypes extends WriterPart * @param string $contentType Content type * @throws Exception */ - private function writeContentType(XMLWriter $xmlWriter, $isDefault, $partName = '', $contentType = '') + private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) { - if ($partName != '' && $contentType != '') { - $element = $isDefault ? 'Default' : 'Override'; - $partAttribute = $isDefault ? 'Extension' : 'PartName'; - $xmlWriter->startElement($element); - $xmlWriter->writeAttribute($partAttribute, $partName); - $xmlWriter->writeAttribute('ContentType', $contentType); - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); + foreach ($parts as $partName => $contentType) { + if ($partName != '' && $contentType != '') { + $partType = $isDefault ? 'Default' : 'Override'; + $partAttribute = $isDefault ? 'Extension' : 'PartName'; + $xmlWriter->startElement($partType); + $xmlWriter->writeAttribute($partAttribute, $partName); + $xmlWriter->writeAttribute('ContentType', $contentType); + $xmlWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); + } } } - - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws Exception - */ - private function getImageMimeType($pFile = '') - { - if (file_exists($pFile)) { - $image = getimagesize($pFile); - return image_type_to_mime_type($image[2]); - } else { - throw new Exception("File $pFile does not exist"); - } - } - - /** - * Write Default XML element - * - * @param XMLWriter $xmlWriter - * @param string $partName Part name - * @param string $contentType Content type - * @deprecated 0.9.2 - * @codeCoverageIgnore - */ - private function writeDefaultContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '') - { - $this->writeContentType($xmlWriter, true, $partName, $contentType); - } - - /** - * Write Override XML element - * - * @param XMLWriter $xmlWriter - * @param string $partName Part name - * @param string $contentType Content type - * @deprecated 0.9.2 - * @codeCoverageIgnore - */ - private function writeOverrideContentType(XMLWriter $xmlWriter, $partName = '', $contentType = '') - { - $this->writeContentType($xmlWriter, false, $partName, $contentType); - } } diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 499aad19..98f158fc 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -103,7 +103,7 @@ class Document extends Base { $settings = $section->getSettings(); $headers = $section->getHeaders(); - $footer = $section->getFooter(); + $footers = $section->getFooters(); $pgSzW = $settings->getPageSizeW(); $pgSzH = $settings->getPageSizeH(); $orientation = $settings->getOrientation(); @@ -139,19 +139,19 @@ class Document extends Base $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->endElement(); } - if ($section->hasDifferentFirstPage()) { - $xmlWriter->startElement('w:titlePg'); - $xmlWriter->endElement(); - } - // Footer reference - if (!is_null($footer)) { + foreach ($footers as &$footer) { $rId = $footer->getRelationId(); $xmlWriter->startElement('w:footerReference'); - $xmlWriter->writeAttribute('w:type', 'default'); + $xmlWriter->writeAttribute('w:type', $footer->getType()); $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->endElement(); } + // Different first page + if ($section->hasDifferentFirstPage()) { + $xmlWriter->startElement('w:titlePg'); + $xmlWriter->endElement(); + } // Page size & orientation $xmlWriter->startElement('w:pgSz'); diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index bbf0634c..d7552410 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -29,13 +29,13 @@ class Rels extends WriterPart */ public function writeMainRels() { - $rels = array( - 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument', + $xmlRels = array( 'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties', 'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties', + 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument', ); $xmlWriter = $this->getXmlWriter(); - $this->writeRels($xmlWriter, $rels); + $this->writeRels($xmlWriter, $xmlRels); return $xmlWriter->getData(); } @@ -47,7 +47,7 @@ class Rels extends WriterPart */ public function writeDocRels($mediaRels) { - $rels = array( + $xmlRels = array( 'styles.xml' => 'officeDocument/2006/relationships/styles', 'numbering.xml' => 'officeDocument/2006/relationships/numbering', 'settings.xml' => 'officeDocument/2006/relationships/settings', @@ -56,7 +56,7 @@ class Rels extends WriterPart 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable', ); $xmlWriter = $this->getXmlWriter(); - $this->writeRels($xmlWriter, $rels, $mediaRels); + $this->writeRels($xmlWriter, $xmlRels, $mediaRels); return $xmlWriter->getData(); } @@ -79,20 +79,24 @@ class Rels extends WriterPart * Write relationships * * @param XMLWriter $xmlWriter - * @param null|array $rels + * @param null|array $xmlRels * @param null|array $mediaRels * @param integer $id */ - private function writeRels(XMLWriter $xmlWriter, $rels = null, $mediaRels = null, $id = 1) + private function writeRels(XMLWriter $xmlWriter, $xmlRels = null, $mediaRels = null, $id = 1) { $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('Relationships'); $xmlWriter->writeAttribute('xmlns', self::RELS_BASE . 'package/2006/relationships'); - if (is_array($rels)) { - foreach ($rels as $target => $type) { + + // XML files relationships + if (is_array($xmlRels)) { + foreach ($xmlRels as $target => $type) { $this->writeRel($xmlWriter, $id++, $type, $target); } } + + // Media relationships if (!is_null($mediaRels) && is_array($mediaRels)) { $mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'); foreach ($mediaRels as $mediaRel) { diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index c7b35faf..f0305f7f 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -28,6 +28,10 @@ class Styles extends Base */ public function writeStyles(PhpWord $phpWord = null) { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php index 268f66e8..49b59b20 100644 --- a/tests/PhpWord/Tests/Container/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -40,10 +40,10 @@ class SectionTest extends \PHPUnit_Framework_TestCase /** * Get footer */ - public function testGetFooter() + public function testGetFooters() { $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getFooter(), 'footer', new Section(0)); + $this->assertAttributeEquals($oSection->getFooters(), 'footers', new Section(0)); } /** diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 3df52e4a..14a38c2d 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -25,7 +25,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testGetSectionMediaElementsWithNull() { - $this->assertEquals(Media::getMediaElements('section'), array()); + $this->assertEquals(Media::getElements('section'), array()); } /** @@ -33,7 +33,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testCountSectionMediaElementsWithNull() { - $this->assertEquals(Media::countMediaElements('section'), 0); + $this->assertEquals(Media::countElements('section'), 0); } /** @@ -44,13 +44,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase $local = __DIR__ . "/_files/images/mars.jpg"; $object = __DIR__ . "/_files/documents/sheet.xls"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addMediaElement('section', 'image', $local, new Image($local)); - Media::addMediaElement('section', 'image', $local, new Image($local)); - Media::addMediaElement('section', 'image', $remote, new Image($local)); - Media::addMediaElement('section', 'object', $object); - Media::addMediaElement('section', 'object', $object); + Media::addElement('section', 'image', $local, new Image($local)); + Media::addElement('section', 'image', $local, new Image($local)); + Media::addElement('section', 'image', $remote, new Image($local)); + Media::addElement('section', 'object', $object); + Media::addElement('section', 'object', $object); - $this->assertEquals(3, Media::countMediaElements('section')); + $this->assertEquals(3, Media::countElements('section')); } /** @@ -58,12 +58,12 @@ class MediaTest extends \PHPUnit_Framework_TestCase */ public function testAddSectionLinkElement() { - $expected = Media::countMediaElements('section') + 1; - $actual = Media::addMediaElement('section', 'link', 'http://test.com'); + $expected = Media::countElements('section') + 1; + $actual = Media::addElement('section', 'link', 'http://test.com'); $this->assertEquals($expected, $actual); - $this->assertEquals(1, Media::countMediaElements('section', 'link')); - $this->assertEquals(1, count(Media::getMediaElements('section', 'link'))); + $this->assertEquals(1, Media::countElements('section', 'link')); + $this->assertEquals(1, count(Media::getElements('section', 'link'))); } /** @@ -73,13 +73,13 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addMediaElement('header1', 'image', $local, new Image($local)); - Media::addMediaElement('header1', 'image', $local, new Image($local)); - Media::addMediaElement('header1', 'image', $remote, new Image($remote)); + Media::addElement('header1', 'image', $local, new Image($local)); + Media::addElement('header1', 'image', $local, new Image($local)); + Media::addElement('header1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countMediaElements('header1')); - $this->assertEquals(2, count(Media::getMediaElements('header1'))); - $this->assertEmpty(Media::getMediaElements('header2')); + $this->assertEquals(2, Media::countElements('header1')); + $this->assertEquals(2, count(Media::getElements('header1'))); + $this->assertEmpty(Media::getElements('header2')); } /** @@ -89,13 +89,24 @@ class MediaTest extends \PHPUnit_Framework_TestCase { $local = __DIR__ . "/_files/images/mars.jpg"; $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; - Media::addMediaElement('footer1', 'image', $local, new Image($local)); - Media::addMediaElement('footer1', 'image', $local, new Image($local)); - Media::addMediaElement('footer1', 'image', $remote, new Image($remote)); + Media::addElement('footer1', 'image', $local, new Image($local)); + Media::addElement('footer1', 'image', $local, new Image($local)); + Media::addElement('footer1', 'image', $remote, new Image($remote)); - $this->assertEquals(2, Media::countMediaElements('footer1')); + $this->assertEquals(2, Media::countElements('footer1')); Media::reset(); - $this->assertEquals(0, Media::countMediaElements('footer1')); + $this->assertEquals(0, Media::countElements('footer1')); + } + + /** + * Add image element exception + * + * @expectedException Exception + * @expectedExceptionMessage Image object not assigned. + */ + public function testAddElementImageException() + { + Media::addElement('section', 'image', __DIR__ . "/_files/images/mars.jpg"); } } From 14664d33f62dfbee6d1f982de49a69c19d01db13 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 6 Apr 2014 00:56:48 +0700 Subject: [PATCH 059/146] Update changelog and documentation --- CHANGELOG.md | 1 + docs/elements.rst | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76dfcbd9..fcdc83de 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 - Template: Ability to find & replace variables in headers & footers - @dgudgeon GH-190 - Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira GH-191 +- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb GH-189 ### Bugfixes diff --git a/docs/elements.rst b/docs/elements.rst index bded72b8..54925551 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -316,7 +316,14 @@ Your TOC can only be generated if you have add at least one title (See .. code-block:: php - $section->addTOC([$fontStyle], [$tocStyle]); + $section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); + +- ``$fontStyle``: See font style section +- ``$tocStyle``: See available options below +- ``$minDepth``: Minimum depth of header to be shown. Default 1 +- ``$maxDepth``: Maximum depth of header to be shown. Default 9 + +Options for ``$tocStyle``: - ``tabLeader`` Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. From 76205c603c7a43b3e08b1962eacb83d595cfad1f Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 6 Apr 2014 01:10:04 +0700 Subject: [PATCH 060/146] Update TOC tests --- tests/PhpWord/Tests/TOCTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 8234a20f..a41f3a8d 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -64,15 +64,16 @@ class TOCTest extends \PHPUnit_Framework_TestCase 'Heading 2' => 2, 'Heading 3' => 3, ); + $toc = new TOC(); foreach ($titles as $text => $depth) { - $response = TOC::addTitle($text, $depth); + $response = $toc->addTitle($text, $depth); } $this->assertEquals($anchor, $response[0]); $this->assertEquals($bookmark, $response[1]); $i = 0; - $savedTitles = TOC::getTitles(); + $savedTitles = $toc->getTitles(); foreach ($titles as $text => $depth) { $this->assertEquals($text, $savedTitles[$i]['text']); $this->assertEquals($depth, $savedTitles[$i]['depth']); From 8d2c6ebd165b08086b0ae4e84d26517c3c6c9623 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 6 Apr 2014 11:52:16 +0700 Subject: [PATCH 061/146] Fix TOCTest error --- tests/PhpWord/Tests/TOCTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index a5f509c9..2b9d50e7 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -81,7 +81,7 @@ class TOCTest extends \PHPUnit_Framework_TestCase } TOC::reset(); - $this->assertEquals(0, count(TOC::getTitles())); + $this->assertEquals(0, count($toc->getTitles())); } From a218202dbdbe1d9f5d3da2d43598d4efff71194a Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 6 Apr 2014 15:19:09 +0700 Subject: [PATCH 062/146] Enhance unit tests --- src/PhpWord/Container/Section.php | 2 ++ src/PhpWord/Element/Image.php | 13 +++++++--- src/PhpWord/TOC.php | 2 ++ src/PhpWord/Writer/Word2007.php | 3 ++- src/PhpWord/Writer/Word2007/ContentTypes.php | 3 +-- tests/PhpWord/Tests/Container/FooterTest.php | 2 ++ tests/PhpWord/Tests/Container/HeaderTest.php | 12 +++++++++ tests/PhpWord/Tests/Container/SectionTest.php | 25 +++++++++++++++++++ tests/PhpWord/Tests/Element/ImageTest.php | 10 ++++++++ 9 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index 01e7fafe..26823df4 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -97,6 +97,8 @@ class Section extends Container * * @param mixed $styleFont * @param mixed $styleTOC + * @param integer $minDepth + * @param integer $maxDepth * @return TOC */ public function addTOC($styleFont = null, $styleTOC = null, $minDepth = 1, $maxDepth = 9) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index ec82665e..fec8791c 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -102,10 +102,13 @@ class Image extends Element // Check supported types if ($this->isMemImage) { $supportedTypes = array('image/jpeg', 'image/gif', 'image/png'); - $imgData = getimagesize($source); + $imgData = @getimagesize($source); + if (!is_array($imgData)) { + throw new InvalidImageException(); + } $this->imageType = $imgData['mime']; // string if (!in_array($this->imageType, $supportedTypes)) { - throw new UnsupportedImageTypeException; + throw new UnsupportedImageTypeException(); } } else { $supportedTypes = array( @@ -114,17 +117,19 @@ class Image extends Element \IMAGETYPE_TIFF_II, \IMAGETYPE_TIFF_MM ); if (!file_exists($source)) { - throw new InvalidImageException; + throw new InvalidImageException(); } $imgData = getimagesize($source); if (function_exists('exif_imagetype')) { $this->imageType = exif_imagetype($source); } else { + // @codeCoverageIgnoreStart $tmp = getimagesize($source); $this->imageType = $tmp[2]; + // @codeCoverageIgnoreEnd } if (!in_array($this->imageType, $supportedTypes)) { - throw new UnsupportedImageTypeException; + throw new UnsupportedImageTypeException(); } $this->imageType = \image_type_to_mime_type($this->imageType); } diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index a992cd55..2793d2f0 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -73,6 +73,8 @@ class TOC * * @param mixed $styleFont * @param array $styleTOC + * @param integer $minDepth + * @param integer $maxDepth */ public function __construct($styleFont = null, $styleTOC = null, $minDepth = 1, $maxDepth = 9) { diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index f7b49cfe..8fe90339 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -229,7 +229,8 @@ class Word2007 extends Writer implements IWriter /** * Add header/footer content * - * @param PhpOffice\PhpWord\Container\Section $section + * @param \PhpOffice\PhpWord\Container\Section $section + * @param mixed $objZip * @param string $elmType * @param integer $rID */ diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 7b371b07..8eb10bc1 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -60,9 +60,8 @@ class ContentTypes extends WriterPart * Write content types element * * @param XMLWriter $xmlWriter XML Writer + * @param array $parts * @param boolean $isDefault - * @param string $partName Part name - * @param string $contentType Content type * @throws Exception */ private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) diff --git a/tests/PhpWord/Tests/Container/FooterTest.php b/tests/PhpWord/Tests/Container/FooterTest.php index bcbf45a9..db982dc5 100644 --- a/tests/PhpWord/Tests/Container/FooterTest.php +++ b/tests/PhpWord/Tests/Container/FooterTest.php @@ -162,6 +162,8 @@ class FooterTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oFooter->setRelationId($iVal); + $this->assertEquals($oFooter->getRelationId(), $iVal); + $this->assertEquals(Footer::AUTO, $oFooter->getType()); } } diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Container/HeaderTest.php index 9d13d57c..ef1703f3 100644 --- a/tests/PhpWord/Tests/Container/HeaderTest.php +++ b/tests/PhpWord/Tests/Container/HeaderTest.php @@ -231,4 +231,16 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $header = new Header(1); $header->addFootnote(); } + + /** + * Set/get type + */ + public function testSetGetType() + { + $object = new Header(1); + $this->assertEquals(Header::AUTO, $object->getType()); + + $object->setType('ODD'); + $this->assertEquals(Header::AUTO, $object->getType()); + } } diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Container/SectionTest.php index 49b59b20..e077ff82 100644 --- a/tests/PhpWord/Tests/Container/SectionTest.php +++ b/tests/PhpWord/Tests/Container/SectionTest.php @@ -9,7 +9,9 @@ namespace PhpOffice\PhpWord\Tests\Container; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Container\Header; use PhpOffice\PhpWord\Style; /** @@ -141,4 +143,27 @@ class SectionTest extends \PHPUnit_Framework_TestCase } $this->assertFalse($object->hasDifferentFirstPage()); } + + /** + * Add header has different first page + */ + public function testHasDifferentFirstPage() + { + $object = new Section(1); + $header = $object->addHeader(); + $header->setType(Header::FIRST); + $this->assertTrue($object->hasDifferentFirstPage()); + } + + /** + * Add header exception + * + * @expectedException Exception + * @expectedExceptionMesssage Invalid header/footer type. + */ + public function testAddHeaderException() + { + $object = new Section(1); + $header = $object->addHeader('ODD'); + } } diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index b0c3d88c..5b9aaa45 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -192,4 +192,14 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oImage->getImageFunction(), null); $this->assertEquals($oImage->getImageType(), 'image/tiff'); } + + /** + * Test PHP Image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + */ + public function testPhpImage() + { + $object = new Image('test.php'); + } } From 177c523799664251de93289170e26f488b19823b Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 6 Apr 2014 18:03:03 +0700 Subject: [PATCH 063/146] Remove underscore prefix from all private properties name --- CHANGELOG.md | 1 + src/PhpWord/Container/Section.php | 4 +- src/PhpWord/Container/Settings.php | 181 ++++++++++---------- src/PhpWord/Element/Element.php | 4 +- src/PhpWord/Style.php | 4 +- src/PhpWord/Style/Cell.php | 129 +++++++------- src/PhpWord/Style/Font.php | 103 +++++------ src/PhpWord/Style/Image.php | 43 ++--- src/PhpWord/Style/ListItem.php | 11 +- src/PhpWord/Style/Paragraph.php | 92 +++++----- src/PhpWord/Style/Row.php | 21 ++- src/PhpWord/Style/TOC.php | 24 +-- src/PhpWord/Style/Tab.php | 28 +-- src/PhpWord/Style/Table.php | 180 +++++++++---------- src/PhpWord/Style/Tabs.php | 6 +- src/PhpWord/TOC.php | 8 +- tests/PhpWord/Tests/Style/CellTest.php | 6 +- tests/PhpWord/Tests/Style/FontTest.php | 4 +- tests/PhpWord/Tests/Style/ImageTest.php | 2 +- tests/PhpWord/Tests/Style/ListItemTest.php | 2 +- tests/PhpWord/Tests/Style/ParagraphTest.php | 6 +- tests/PhpWord/Tests/Style/RowTest.php | 2 +- tests/PhpWord/Tests/Style/TOCTest.php | 2 +- tests/PhpWord/Tests/Style/TableTest.php | 6 +- 24 files changed, 446 insertions(+), 423 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1ea897..5c3ed441 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - Container: Create new Container abstract class - @ivanlanin GH-187 - Element: Create new Element abstract class - @ivanlanin GH-187 - Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 +- General: Remove underscore prefix from all private properties name ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index 26823df4..dae4f26c 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -66,8 +66,8 @@ class Section extends Container { if (!is_null($settings) && is_array($settings)) { foreach ($settings as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $this->settings->setSettingValue($key, $value); } diff --git a/src/PhpWord/Container/Settings.php b/src/PhpWord/Container/Settings.php index daf5d13b..762d45c3 100644 --- a/src/PhpWord/Container/Settings.php +++ b/src/PhpWord/Container/Settings.php @@ -19,119 +19,119 @@ class Settings * * @var int */ - private $_defaultPageSizeW = 11906; + private $defaultPageSizeW = 11906; /** * Default Page Size Height * * @var int */ - private $_defaultPageSizeH = 16838; + private $defaultPageSizeH = 16838; /** * Page Orientation * * @var string */ - private $_orientation; + private $orientation; /** * Page Margin Top * * @var int */ - private $_marginTop; + private $marginTop; /** * Page Margin Left * * @var int */ - private $_marginLeft; + private $marginLeft; /** * Page Margin Right * * @var int */ - private $_marginRight; + private $marginRight; /** * Page Margin Bottom * * @var int */ - private $_marginBottom; + private $marginBottom; /** * Page Size Width * * @var int */ - private $_pageSizeW; + private $pageSizeW; /** * Page Size Height * * @var int */ - private $_pageSizeH; + private $pageSizeH; /** * Page Border Top Size * * @var int */ - private $_borderTopSize; + private $borderTopSize; /** * Page Border Top Color * * @var int */ - private $_borderTopColor; + private $borderTopColor; /** * Page Border Left Size * * @var int */ - private $_borderLeftSize; + private $borderLeftSize; /** * Page Border Left Color * * @var int */ - private $_borderLeftColor; + private $borderLeftColor; /** * Page Border Right Size * * @var int */ - private $_borderRightSize; + private $borderRightSize; /** * Page Border Right Color * * @var int */ - private $_borderRightColor; + private $borderRightColor; /** * Page Border Bottom Size * * @var int */ - private $_borderBottomSize; + private $borderBottomSize; /** * Page Border Bottom Color * * @var int */ - private $_borderBottomColor; + private $borderBottomColor; /** * Page Numbering Start @@ -159,14 +159,14 @@ class Settings * * @var int */ - private $_colsNum; + private $colsNum; /** * Section spacing between columns * * @var int */ - private $_colsSpace; + private $colsSpace; /** * Section break type @@ -180,33 +180,33 @@ class Settings * * @var string */ - private $_breakType; + private $breakType; /** * Create new Section Settings */ public function __construct() { - $this->_orientation = null; - $this->_marginTop = 1418; - $this->_marginLeft = 1418; - $this->_marginRight = 1418; - $this->_marginBottom = 1134; - $this->_pageSizeW = $this->_defaultPageSizeW; - $this->_pageSizeH = $this->_defaultPageSizeH; - $this->_borderTopSize = null; - $this->_borderTopColor = null; - $this->_borderLeftSize = null; - $this->_borderLeftColor = null; - $this->_borderRightSize = null; - $this->_borderRightColor = null; - $this->_borderBottomSize = null; - $this->_borderBottomColor = null; + $this->orientation = null; + $this->marginTop = 1418; + $this->marginLeft = 1418; + $this->marginRight = 1418; + $this->marginBottom = 1134; + $this->pageSizeW = $this->defaultPageSizeW; + $this->pageSizeH = $this->defaultPageSizeH; + $this->borderTopSize = null; + $this->borderTopColor = null; + $this->borderLeftSize = null; + $this->borderLeftColor = null; + $this->borderRightSize = null; + $this->borderRightColor = null; + $this->borderBottomSize = null; + $this->borderBottomColor = null; $this->headerHeight = 720; // set default header and footer to 720 twips (.5 inches) $this->footerHeight = 720; - $this->_colsNum = 1; - $this->_colsSpace = 720; - $this->_breakType = null; + $this->colsNum = 1; + $this->colsSpace = 720; + $this->breakType = null; } /** @@ -217,13 +217,16 @@ class Settings */ public function setSettingValue($key, $value) { - if ($key == '_orientation' && $value == 'landscape') { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + if ($key == 'orientation' && $value == 'landscape') { $this->setLandscape(); - } elseif ($key == '_orientation' && is_null($value)) { + } elseif ($key == 'orientation' && is_null($value)) { $this->setPortrait(); - } elseif ($key == '_borderSize') { + } elseif ($key == 'borderSize') { $this->setBorderSize($value); - } elseif ($key == '_borderColor') { + } elseif ($key == 'borderColor') { $this->setBorderColor($value); } else { $this->$key = $value; @@ -237,7 +240,7 @@ class Settings */ public function getMarginTop() { - return $this->_marginTop; + return $this->marginTop; } /** @@ -247,7 +250,7 @@ class Settings */ public function setMarginTop($pValue = '') { - $this->_marginTop = $pValue; + $this->marginTop = $pValue; return $this; } @@ -258,7 +261,7 @@ class Settings */ public function getMarginLeft() { - return $this->_marginLeft; + return $this->marginLeft; } /** @@ -268,7 +271,7 @@ class Settings */ public function setMarginLeft($pValue = '') { - $this->_marginLeft = $pValue; + $this->marginLeft = $pValue; return $this; } @@ -279,7 +282,7 @@ class Settings */ public function getMarginRight() { - return $this->_marginRight; + return $this->marginRight; } /** @@ -289,7 +292,7 @@ class Settings */ public function setMarginRight($pValue = '') { - $this->_marginRight = $pValue; + $this->marginRight = $pValue; return $this; } @@ -300,7 +303,7 @@ class Settings */ public function getMarginBottom() { - return $this->_marginBottom; + return $this->marginBottom; } /** @@ -310,7 +313,7 @@ class Settings */ public function setMarginBottom($pValue = '') { - $this->_marginBottom = $pValue; + $this->marginBottom = $pValue; return $this; } @@ -319,9 +322,9 @@ class Settings */ public function setLandscape() { - $this->_orientation = 'landscape'; - $this->_pageSizeW = $this->_defaultPageSizeH; - $this->_pageSizeH = $this->_defaultPageSizeW; + $this->orientation = 'landscape'; + $this->pageSizeW = $this->defaultPageSizeH; + $this->pageSizeH = $this->defaultPageSizeW; } /** @@ -329,9 +332,9 @@ class Settings */ public function setPortrait() { - $this->_orientation = null; - $this->_pageSizeW = $this->_defaultPageSizeW; - $this->_pageSizeH = $this->_defaultPageSizeH; + $this->orientation = null; + $this->pageSizeW = $this->defaultPageSizeW; + $this->pageSizeH = $this->defaultPageSizeH; } /** @@ -341,7 +344,7 @@ class Settings */ public function getPageSizeW() { - return $this->_pageSizeW; + return $this->pageSizeW; } /** @@ -351,7 +354,7 @@ class Settings */ public function getPageSizeH() { - return $this->_pageSizeH; + return $this->pageSizeH; } /** @@ -361,7 +364,7 @@ class Settings */ public function getOrientation() { - return $this->_orientation; + return $this->orientation; } /** @@ -371,10 +374,10 @@ class Settings */ public function setBorderSize($pValue = null) { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; + $this->borderTopSize = $pValue; + $this->borderLeftSize = $pValue; + $this->borderRightSize = $pValue; + $this->borderBottomSize = $pValue; } /** @@ -399,10 +402,10 @@ class Settings */ public function setBorderColor($pValue = null) { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; + $this->borderTopColor = $pValue; + $this->borderLeftColor = $pValue; + $this->borderRightColor = $pValue; + $this->borderBottomColor = $pValue; } /** @@ -427,7 +430,7 @@ class Settings */ public function setBorderTopSize($pValue = null) { - $this->_borderTopSize = $pValue; + $this->borderTopSize = $pValue; } /** @@ -437,7 +440,7 @@ class Settings */ public function getBorderTopSize() { - return $this->_borderTopSize; + return $this->borderTopSize; } /** @@ -447,7 +450,7 @@ class Settings */ public function setBorderTopColor($pValue = null) { - $this->_borderTopColor = $pValue; + $this->borderTopColor = $pValue; } /** @@ -457,7 +460,7 @@ class Settings */ public function getBorderTopColor() { - return $this->_borderTopColor; + return $this->borderTopColor; } /** @@ -467,7 +470,7 @@ class Settings */ public function setBorderLeftSize($pValue = null) { - $this->_borderLeftSize = $pValue; + $this->borderLeftSize = $pValue; } /** @@ -477,7 +480,7 @@ class Settings */ public function getBorderLeftSize() { - return $this->_borderLeftSize; + return $this->borderLeftSize; } /** @@ -487,7 +490,7 @@ class Settings */ public function setBorderLeftColor($pValue = null) { - $this->_borderLeftColor = $pValue; + $this->borderLeftColor = $pValue; } /** @@ -497,7 +500,7 @@ class Settings */ public function getBorderLeftColor() { - return $this->_borderLeftColor; + return $this->borderLeftColor; } /** @@ -507,7 +510,7 @@ class Settings */ public function setBorderRightSize($pValue = null) { - $this->_borderRightSize = $pValue; + $this->borderRightSize = $pValue; } /** @@ -517,7 +520,7 @@ class Settings */ public function getBorderRightSize() { - return $this->_borderRightSize; + return $this->borderRightSize; } /** @@ -527,7 +530,7 @@ class Settings */ public function setBorderRightColor($pValue = null) { - $this->_borderRightColor = $pValue; + $this->borderRightColor = $pValue; } /** @@ -537,7 +540,7 @@ class Settings */ public function getBorderRightColor() { - return $this->_borderRightColor; + return $this->borderRightColor; } /** @@ -547,7 +550,7 @@ class Settings */ public function setBorderBottomSize($pValue = null) { - $this->_borderBottomSize = $pValue; + $this->borderBottomSize = $pValue; } /** @@ -557,7 +560,7 @@ class Settings */ public function getBorderBottomSize() { - return $this->_borderBottomSize; + return $this->borderBottomSize; } /** @@ -567,7 +570,7 @@ class Settings */ public function setBorderBottomColor($pValue = null) { - $this->_borderBottomColor = $pValue; + $this->borderBottomColor = $pValue; } /** @@ -577,7 +580,7 @@ class Settings */ public function getBorderBottomColor() { - return $this->_borderBottomColor; + return $this->borderBottomColor; } /** @@ -660,7 +663,7 @@ class Settings if (!is_numeric($pValue)) { $pValue = 1; } - $this->_colsNum = $pValue; + $this->colsNum = $pValue; return $this; } @@ -671,7 +674,7 @@ class Settings */ public function getColsNum() { - return $this->_colsNum; + return $this->colsNum; } /** @@ -684,7 +687,7 @@ class Settings if (!is_numeric($pValue)) { $pValue = 720; } - $this->_colsSpace = $pValue; + $this->colsSpace = $pValue; return $this; } @@ -695,7 +698,7 @@ class Settings */ public function getColsSpace() { - return $this->_colsSpace; + return $this->colsSpace; } /** @@ -705,7 +708,7 @@ class Settings */ public function setBreakType($pValue = null) { - $this->_breakType = $pValue; + $this->breakType = $pValue; return $this; } @@ -716,6 +719,6 @@ class Settings */ public function getBreakType() { - return $this->_breakType; + return $this->breakType; } } diff --git a/src/PhpWord/Element/Element.php b/src/PhpWord/Element/Element.php index ec0dbc5c..6cebd0d5 100644 --- a/src/PhpWord/Element/Element.php +++ b/src/PhpWord/Element/Element.php @@ -49,8 +49,8 @@ abstract class Element { if (!is_null($styleValue) && is_array($styleValue)) { foreach ($styleValue as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $styleObject->setStyleValue($key, $value); } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 3db67cb5..e883b9ed 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -141,8 +141,8 @@ class Style { if (!array_key_exists($styleName, self::$styles)) { foreach ($styleValues as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $styleObject->setStyleValue($key, $value); } diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 3949cddd..1fbed6e7 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -22,91 +22,91 @@ class Cell * * @var string */ - private $_valign; + private $valign; /** * Text Direction * * @var string */ - private $_textDirection; + private $textDirection; /** * Background-Color * * @var string */ - private $_bgColor; + private $bgColor; /** * Border Top Size * * @var int */ - private $_borderTopSize; + private $borderTopSize; /** * Border Top Color * * @var string */ - private $_borderTopColor; + private $borderTopColor; /** * Border Left Size * * @var int */ - private $_borderLeftSize; + private $borderLeftSize; /** * Border Left Color * * @var string */ - private $_borderLeftColor; + private $borderLeftColor; /** * Border Right Size * * @var int */ - private $_borderRightSize; + private $borderRightSize; /** * Border Right Color * * @var string */ - private $_borderRightColor; + private $borderRightColor; /** * Border Bottom Size * * @var int */ - private $_borderBottomSize; + private $borderBottomSize; /** * Border Bottom Color * * @var string */ - private $_borderBottomColor; + private $borderBottomColor; /** * Border Default Color * * @var string */ - private $_defaultBorderColor; + private $defaultBorderColor; /** * colspan * * @var integer */ - private $_gridSpan = null; + private $gridSpan = null; /** * rowspan (restart, continue) @@ -116,25 +116,25 @@ class Cell * * @var string */ - private $_vMerge = null; + private $vMerge = null; /** * Create a new Cell Style */ public function __construct() { - $this->_valign = null; - $this->_textDirection = null; - $this->_bgColor = null; - $this->_borderTopSize = null; - $this->_borderTopColor = null; - $this->_borderLeftSize = null; - $this->_borderLeftColor = null; - $this->_borderRightSize = null; - $this->_borderRightColor = null; - $this->_borderBottomSize = null; - $this->_borderBottomColor = null; - $this->_defaultBorderColor = '000000'; + $this->valign = null; + $this->textDirection = null; + $this->bgColor = null; + $this->borderTopSize = null; + $this->borderTopColor = null; + $this->borderLeftSize = null; + $this->borderLeftColor = null; + $this->borderRightSize = null; + $this->borderRightColor = null; + $this->borderBottomSize = null; + $this->borderBottomColor = null; + $this->defaultBorderColor = '000000'; } /** @@ -145,9 +145,12 @@ class Cell */ public function setStyleValue($key, $value) { - if ($key == '_borderSize') { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + if ($key == 'borderSize') { $this->setBorderSize($value); - } elseif ($key == '_borderColor') { + } elseif ($key == 'borderColor') { $this->setBorderColor($value); } else { $this->$key = $value; @@ -159,7 +162,7 @@ class Cell */ public function getVAlign() { - return $this->_valign; + return $this->valign; } /** @@ -169,7 +172,7 @@ class Cell */ public function setVAlign($pValue = null) { - $this->_valign = $pValue; + $this->valign = $pValue; } /** @@ -177,7 +180,7 @@ class Cell */ public function getTextDirection() { - return $this->_textDirection; + return $this->textDirection; } /** @@ -187,7 +190,7 @@ class Cell */ public function setTextDirection($pValue = null) { - $this->_textDirection = $pValue; + $this->textDirection = $pValue; } /** @@ -195,7 +198,7 @@ class Cell */ public function getBgColor() { - return $this->_bgColor; + return $this->bgColor; } /** @@ -205,7 +208,7 @@ class Cell */ public function setBgColor($pValue = null) { - $this->_bgColor = $pValue; + $this->bgColor = $pValue; } /** @@ -215,10 +218,10 @@ class Cell */ public function setBorderSize($pValue = null) { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; + $this->borderTopSize = $pValue; + $this->borderLeftSize = $pValue; + $this->borderRightSize = $pValue; + $this->borderBottomSize = $pValue; } /** @@ -241,10 +244,10 @@ class Cell */ public function setBorderColor($pValue = null) { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; + $this->borderTopColor = $pValue; + $this->borderLeftColor = $pValue; + $this->borderRightColor = $pValue; + $this->borderBottomColor = $pValue; } /** @@ -267,7 +270,7 @@ class Cell */ public function setBorderTopSize($pValue = null) { - $this->_borderTopSize = $pValue; + $this->borderTopSize = $pValue; } /** @@ -275,7 +278,7 @@ class Cell */ public function getBorderTopSize() { - return $this->_borderTopSize; + return $this->borderTopSize; } /** @@ -285,7 +288,7 @@ class Cell */ public function setBorderTopColor($pValue = null) { - $this->_borderTopColor = $pValue; + $this->borderTopColor = $pValue; } /** @@ -293,7 +296,7 @@ class Cell */ public function getBorderTopColor() { - return $this->_borderTopColor; + return $this->borderTopColor; } /** @@ -303,7 +306,7 @@ class Cell */ public function setBorderLeftSize($pValue = null) { - $this->_borderLeftSize = $pValue; + $this->borderLeftSize = $pValue; } /** @@ -311,7 +314,7 @@ class Cell */ public function getBorderLeftSize() { - return $this->_borderLeftSize; + return $this->borderLeftSize; } /** @@ -321,7 +324,7 @@ class Cell */ public function setBorderLeftColor($pValue = null) { - $this->_borderLeftColor = $pValue; + $this->borderLeftColor = $pValue; } /** @@ -329,7 +332,7 @@ class Cell */ public function getBorderLeftColor() { - return $this->_borderLeftColor; + return $this->borderLeftColor; } /** @@ -339,7 +342,7 @@ class Cell */ public function setBorderRightSize($pValue = null) { - $this->_borderRightSize = $pValue; + $this->borderRightSize = $pValue; } /** @@ -347,7 +350,7 @@ class Cell */ public function getBorderRightSize() { - return $this->_borderRightSize; + return $this->borderRightSize; } /** @@ -357,7 +360,7 @@ class Cell */ public function setBorderRightColor($pValue = null) { - $this->_borderRightColor = $pValue; + $this->borderRightColor = $pValue; } /** @@ -365,7 +368,7 @@ class Cell */ public function getBorderRightColor() { - return $this->_borderRightColor; + return $this->borderRightColor; } /** @@ -375,7 +378,7 @@ class Cell */ public function setBorderBottomSize($pValue = null) { - $this->_borderBottomSize = $pValue; + $this->borderBottomSize = $pValue; } /** @@ -383,7 +386,7 @@ class Cell */ public function getBorderBottomSize() { - return $this->_borderBottomSize; + return $this->borderBottomSize; } /** @@ -393,7 +396,7 @@ class Cell */ public function setBorderBottomColor($pValue = null) { - $this->_borderBottomColor = $pValue; + $this->borderBottomColor = $pValue; } /** @@ -401,7 +404,7 @@ class Cell */ public function getBorderBottomColor() { - return $this->_borderBottomColor; + return $this->borderBottomColor; } /** @@ -409,7 +412,7 @@ class Cell */ public function getDefaultBorderColor() { - return $this->_defaultBorderColor; + return $this->defaultBorderColor; } /** @@ -419,7 +422,7 @@ class Cell */ public function setGridSpan($pValue = null) { - $this->_gridSpan = $pValue; + $this->gridSpan = $pValue; } /** @@ -427,7 +430,7 @@ class Cell */ public function getGridSpan() { - return $this->_gridSpan; + return $this->gridSpan; } /** @@ -437,7 +440,7 @@ class Cell */ public function setVMerge($pValue = null) { - $this->_vMerge = $pValue; + $this->vMerge = $pValue; } /** @@ -445,6 +448,6 @@ class Cell */ public function getVMerge() { - return $this->_vMerge; + return $this->vMerge; } } diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 69520804..999fc3fa 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -56,91 +56,91 @@ class Font * * @var string */ - private $_type; + private $type; /** * Paragraph style * * @var \PhpOffice\PhpWord\Style\Paragraph */ - private $_paragraphStyle; + private $paragraphStyle; /** * Font name * * @var int|float */ - private $_name = PhpWord::DEFAULT_FONT_NAME; + private $name = PhpWord::DEFAULT_FONT_NAME; /** * Font size * * @var int|float */ - private $_size = PhpWord::DEFAULT_FONT_SIZE; + private $size = PhpWord::DEFAULT_FONT_SIZE; /** * Bold * * @var bool */ - private $_bold = false; + private $bold = false; /** * Italic * * @var bool */ - private $_italic = false; + private $italic = false; /** * Superscript * * @var bool */ - private $_superScript = false; + private $superScript = false; /** * Subscript * * @var bool */ - private $_subScript = false; + private $subScript = false; /** * Undeline * * @var string */ - private $_underline = self::UNDERLINE_NONE; + private $underline = self::UNDERLINE_NONE; /** * Strikethrough * * @var bool */ - private $_strikethrough = false; + private $strikethrough = false; /** * Font color * * @var string */ - private $_color = PhpWord::DEFAULT_FONT_COLOR; + private $color = PhpWord::DEFAULT_FONT_COLOR; /** * Foreground/highlight * * @var string */ - private $_fgColor = null; + private $fgColor = null; /** * Background color * * @var string */ - private $_bgColor = null; + private $bgColor = null; /** * Text line height * @@ -159,7 +159,7 @@ class Font * * @var string */ - private $_hint = PhpWord::DEFAULT_FONT_CONTENT_TYPE; + private $hint = PhpWord::DEFAULT_FONT_CONTENT_TYPE; /** * Create new font style @@ -169,15 +169,15 @@ class Font */ public function __construct($type = 'text', $paragraphStyle = null) { - $this->_type = $type; + $this->type = $type; if ($paragraphStyle instanceof Paragraph) { - $this->_paragraphStyle = $paragraphStyle; + $this->paragraphStyle = $paragraphStyle; } elseif (is_array($paragraphStyle)) { - $this->_paragraphStyle = new Paragraph; - $this->_paragraphStyle->setArrayStyle($paragraphStyle); + $this->paragraphStyle = new Paragraph; + $this->paragraphStyle->setArrayStyle($paragraphStyle); } else { - $this->_paragraphStyle = $paragraphStyle; + $this->paragraphStyle = $paragraphStyle; } } @@ -193,8 +193,8 @@ class Font if ($key === 'line-height') { $this->setLineHeight($value); null; - } elseif (substr($key, 0, 1) !== '_') { - $key = '_' . $key; + } elseif (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $this->setStyleValue($key, $value); } @@ -210,7 +210,10 @@ class Font */ public function setStyleValue($key, $value) { - $method = 'set' . substr($key, 1); + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + $method = 'set' . $key; if (method_exists($this, $method)) { $this->$method($value); } @@ -223,7 +226,7 @@ class Font */ public function getName() { - return $this->_name; + return $this->name; } /** @@ -237,7 +240,7 @@ class Font if (is_null($pValue) || $pValue == '') { $pValue = PhpWord::DEFAULT_FONT_NAME; } - $this->_name = $pValue; + $this->name = $pValue; return $this; } @@ -249,7 +252,7 @@ class Font */ public function getSize() { - return $this->_size; + return $this->size; } /** @@ -263,7 +266,7 @@ class Font if (!is_numeric($pValue)) { $pValue = PhpWord::DEFAULT_FONT_SIZE; } - $this->_size = $pValue; + $this->size = $pValue; return $this; } @@ -274,7 +277,7 @@ class Font */ public function getBold() { - return $this->_bold; + return $this->bold; } /** @@ -288,7 +291,7 @@ class Font if (!is_bool($pValue)) { $pValue = false; } - $this->_bold = $pValue; + $this->bold = $pValue; return $this; } @@ -299,7 +302,7 @@ class Font */ public function getItalic() { - return $this->_italic; + return $this->italic; } /** @@ -313,7 +316,7 @@ class Font if (!is_bool($pValue)) { $pValue = false; } - $this->_italic = $pValue; + $this->italic = $pValue; return $this; } @@ -324,7 +327,7 @@ class Font */ public function getSuperScript() { - return $this->_superScript; + return $this->superScript; } /** @@ -338,8 +341,8 @@ class Font if (!is_bool($pValue)) { $pValue = false; } - $this->_superScript = $pValue; - $this->_subScript = !$pValue; + $this->superScript = $pValue; + $this->subScript = !$pValue; return $this; } @@ -350,7 +353,7 @@ class Font */ public function getSubScript() { - return $this->_subScript; + return $this->subScript; } /** @@ -364,8 +367,8 @@ class Font if (!is_bool($pValue)) { $pValue = false; } - $this->_subScript = $pValue; - $this->_superScript = !$pValue; + $this->subScript = $pValue; + $this->superScript = !$pValue; return $this; } @@ -376,7 +379,7 @@ class Font */ public function getUnderline() { - return $this->_underline; + return $this->underline; } /** @@ -390,7 +393,7 @@ class Font if ($pValue == '') { $pValue = self::UNDERLINE_NONE; } - $this->_underline = $pValue; + $this->underline = $pValue; return $this; } @@ -401,7 +404,7 @@ class Font */ public function getStrikethrough() { - return $this->_strikethrough; + return $this->strikethrough; } /** @@ -415,7 +418,7 @@ class Font if (!is_bool($pValue)) { $pValue = false; } - $this->_strikethrough = $pValue; + $this->strikethrough = $pValue; return $this; } @@ -426,7 +429,7 @@ class Font */ public function getColor() { - return $this->_color; + return $this->color; } /** @@ -440,7 +443,7 @@ class Font if (is_null($pValue) || $pValue == '') { $pValue = PhpWord::DEFAULT_FONT_COLOR; } - $this->_color = $pValue; + $this->color = $pValue; return $this; } @@ -451,7 +454,7 @@ class Font */ public function getFgColor() { - return $this->_fgColor; + return $this->fgColor; } /** @@ -462,7 +465,7 @@ class Font */ public function setFgColor($pValue = null) { - $this->_fgColor = $pValue; + $this->fgColor = $pValue; return $this; } @@ -473,7 +476,7 @@ class Font */ public function getBgColor() { - return $this->_bgColor; + return $this->bgColor; } /** @@ -484,7 +487,7 @@ class Font */ public function setBgColor($pValue = null) { - $this->_bgColor = $pValue; + $this->bgColor = $pValue; return $this; } @@ -495,7 +498,7 @@ class Font */ public function getStyleType() { - return $this->_type; + return $this->type; } /** @@ -505,7 +508,7 @@ class Font */ public function getParagraphStyle() { - return $this->_paragraphStyle; + return $this->paragraphStyle; } /** @@ -547,7 +550,7 @@ class Font */ public function getHint() { - return $this->_hint; + return $this->hint; } /** @@ -561,7 +564,7 @@ class Font if (is_null($pValue) || $pValue == '') { $pValue = PhpWord::DEFAULT_FONT_CONTENT_TYPE; } - $this->_hint = $pValue; + $this->hint = $pValue; return $this; } } diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index f2065a7e..e973f1ac 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -25,21 +25,21 @@ class Image * * @var int */ - private $_width; + private $width; /** * Image width * * @var int */ - private $_height; + private $height; /** * Alignment * * @var string */ - private $_align; + private $align; /** * Wrapping style @@ -53,25 +53,25 @@ class Image * * @var int */ - private $_marginTop; + private $marginTop; /** * Margin Left * * @var int */ - private $_marginLeft; + private $marginLeft; /** * Create new image style */ public function __construct() { - $this->_width = null; - $this->_height = null; - $this->_align = null; - $this->_marginTop = null; - $this->_marginLeft = null; + $this->width = null; + $this->height = null; + $this->align = null; + $this->marginTop = null; + $this->marginLeft = null; $this->setWrappingStyle(self::WRAPPING_STYLE_INLINE); } @@ -83,6 +83,9 @@ class Image */ public function setStyleValue($key, $value) { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } $this->$key = $value; } @@ -91,7 +94,7 @@ class Image */ public function getWidth() { - return $this->_width; + return $this->width; } /** @@ -101,7 +104,7 @@ class Image */ public function setWidth($pValue = null) { - $this->_width = $pValue; + $this->width = $pValue; } /** @@ -109,7 +112,7 @@ class Image */ public function getHeight() { - return $this->_height; + return $this->height; } /** @@ -119,7 +122,7 @@ class Image */ public function setHeight($pValue = null) { - $this->_height = $pValue; + $this->height = $pValue; } /** @@ -127,7 +130,7 @@ class Image */ public function getAlign() { - return $this->_align; + return $this->align; } /** @@ -137,7 +140,7 @@ class Image */ public function setAlign($pValue = null) { - $this->_align = $pValue; + $this->align = $pValue; } /** @@ -147,7 +150,7 @@ class Image */ public function getMarginTop() { - return $this->_marginTop; + return $this->marginTop; } /** @@ -158,7 +161,7 @@ class Image */ public function setMarginTop($pValue = null) { - $this->_marginTop = $pValue; + $this->marginTop = $pValue; return $this; } @@ -169,7 +172,7 @@ class Image */ public function getMarginLeft() { - return $this->_marginLeft; + return $this->marginLeft; } /** @@ -180,7 +183,7 @@ class Image */ public function setMarginLeft($pValue = null) { - $this->_marginLeft = $pValue; + $this->marginLeft = $pValue; return $this; } diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 9c515e07..6681be16 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -24,14 +24,14 @@ class ListItem /** * List Type */ - private $_listType; + private $listType; /** * Create a new ListItem Style */ public function __construct() { - $this->_listType = self::TYPE_BULLET_FILLED; + $this->listType = self::TYPE_BULLET_FILLED; } /** @@ -42,6 +42,9 @@ class ListItem */ public function setStyleValue($key, $value) { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } $this->$key = $value; } @@ -52,7 +55,7 @@ class ListItem */ public function setListType($pValue = self::TYPE_BULLET_FILLED) { - $this->_listType = $pValue; + $this->listType = $pValue; } /** @@ -60,6 +63,6 @@ class ListItem */ public function getListType() { - return $this->_listType; + return $this->listType; } } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index da1c8c05..c55d9db1 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -30,91 +30,91 @@ class Paragraph * * @var string */ - private $_align; + private $align; /** * Space before Paragraph * * @var int */ - private $_spaceBefore; + private $spaceBefore; /** * Space after Paragraph * * @var int */ - private $_spaceAfter; + private $spaceAfter; /** * Spacing between breaks * * @var int */ - private $_spacing; + private $spacing; /** * Set of Custom Tab Stops * * @var array */ - private $_tabs; + private $tabs; /** * Indent by how much * * @var int */ - private $_indent; + private $indent; /** * Hanging by how much * * @var int */ - private $_hanging; + private $hanging; /** * Parent style * * @var string */ - private $_basedOn = 'Normal'; + private $basedOn = 'Normal'; /** * Style for next paragraph * * @var string */ - private $_next; + private $next; /** * Allow first/last line to display on a separate page * * @var bool */ - private $_widowControl = true; + private $widowControl = true; /** * Keep paragraph with next paragraph * * @var bool */ - private $_keepNext = false; + private $keepNext = false; /** * Keep all lines on one page * * @var bool */ - private $_keepLines = false; + private $keepLines = false; /** * Start paragraph on next page * * @var bool */ - private $_pageBreakBefore = false; + private $pageBreakBefore = false; /** * Set style by array @@ -127,8 +127,8 @@ class Paragraph foreach ($style as $key => $value) { if ($key === 'line-height') { null; - } elseif (substr($key, 0, 1) !== '_') { - $key = '_' . $key; + } elseif (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $this->setStyleValue($key, $value); } @@ -144,16 +144,18 @@ class Paragraph */ public function setStyleValue($key, $value) { - if ($key == '_indent' || $key == '_hanging') { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + if ($key == 'indent' || $key == 'hanging') { $value = $value * 720; - } elseif ($key == '_spacing') { + } elseif ($key == 'spacing') { $value += 240; // because line height of 1 matches 240 twips } elseif ($key === 'line-height') { $this->setLineHeight($value); return; } - $this->$key = $value; - $method = 'set' . substr($key, 1); + $method = 'set' . $key; if (method_exists($this, $method)) { $this->$method($value); } @@ -166,7 +168,7 @@ class Paragraph */ public function getAlign() { - return $this->_align; + return $this->align; } /** @@ -181,7 +183,7 @@ class Paragraph // justify becames both $pValue = 'both'; } - $this->_align = $pValue; + $this->align = $pValue; return $this; } @@ -192,7 +194,7 @@ class Paragraph */ public function getSpaceBefore() { - return $this->_spaceBefore; + return $this->spaceBefore; } /** @@ -203,7 +205,7 @@ class Paragraph */ public function setSpaceBefore($pValue = null) { - $this->_spaceBefore = $pValue; + $this->spaceBefore = $pValue; return $this; } @@ -214,7 +216,7 @@ class Paragraph */ public function getSpaceAfter() { - return $this->_spaceAfter; + return $this->spaceAfter; } /** @@ -225,7 +227,7 @@ class Paragraph */ public function setSpaceAfter($pValue = null) { - $this->_spaceAfter = $pValue; + $this->spaceAfter = $pValue; return $this; } @@ -236,7 +238,7 @@ class Paragraph */ public function getSpacing() { - return $this->_spacing; + return $this->spacing; } /** @@ -247,7 +249,7 @@ class Paragraph */ public function setSpacing($pValue = null) { - $this->_spacing = $pValue; + $this->spacing = $pValue; return $this; } @@ -258,7 +260,7 @@ class Paragraph */ public function getIndent() { - return $this->_indent; + return $this->indent; } /** @@ -269,7 +271,7 @@ class Paragraph */ public function setIndent($pValue = null) { - $this->_indent = $pValue; + $this->indent = $pValue; return $this; } @@ -280,7 +282,7 @@ class Paragraph */ public function getHanging() { - return $this->_hanging; + return $this->hanging; } /** @@ -291,7 +293,7 @@ class Paragraph */ public function setHanging($pValue = null) { - $this->_hanging = $pValue; + $this->hanging = $pValue; return $this; } @@ -302,7 +304,7 @@ class Paragraph */ public function getTabs() { - return $this->_tabs; + return $this->tabs; } /** @@ -314,7 +316,7 @@ class Paragraph public function setTabs($pValue = null) { if (is_array($pValue)) { - $this->_tabs = new Tabs($pValue); + $this->tabs = new Tabs($pValue); } return $this; } @@ -326,7 +328,7 @@ class Paragraph */ public function getBasedOn() { - return $this->_basedOn; + return $this->basedOn; } /** @@ -337,7 +339,7 @@ class Paragraph */ public function setBasedOn($pValue = 'Normal') { - $this->_basedOn = $pValue; + $this->basedOn = $pValue; return $this; } @@ -348,7 +350,7 @@ class Paragraph */ public function getNext() { - return $this->_next; + return $this->next; } /** @@ -359,7 +361,7 @@ class Paragraph */ public function setNext($pValue = null) { - $this->_next = $pValue; + $this->next = $pValue; return $this; } @@ -370,7 +372,7 @@ class Paragraph */ public function getWidowControl() { - return $this->_widowControl; + return $this->widowControl; } /** @@ -384,7 +386,7 @@ class Paragraph if (!is_bool($pValue)) { $pValue = true; } - $this->_widowControl = $pValue; + $this->widowControl = $pValue; return $this; } @@ -395,7 +397,7 @@ class Paragraph */ public function getKeepNext() { - return $this->_keepNext; + return $this->keepNext; } /** @@ -409,7 +411,7 @@ class Paragraph if (!is_bool($pValue)) { $pValue = false; } - $this->_keepNext = $pValue; + $this->keepNext = $pValue; return $this; } @@ -420,7 +422,7 @@ class Paragraph */ public function getKeepLines() { - return $this->_keepLines; + return $this->keepLines; } /** @@ -434,7 +436,7 @@ class Paragraph if (!is_bool($pValue)) { $pValue = false; } - $this->_keepLines = $pValue; + $this->keepLines = $pValue; return $this; } @@ -445,7 +447,7 @@ class Paragraph */ public function getPageBreakBefore() { - return $this->_pageBreakBefore; + return $this->pageBreakBefore; } /** @@ -459,7 +461,7 @@ class Paragraph if (!is_bool($pValue)) { $pValue = false; } - $this->_pageBreakBefore = $pValue; + $this->pageBreakBefore = $pValue; return $this; } diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 2b714024..113baaf2 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -19,21 +19,21 @@ class Row * * @var bool */ - private $_tblHeader = false; + private $tblHeader = false; /** * Table row cannot break across pages * * @var bool */ - private $_cantSplit = false; + private $cantSplit = false; /** * Table row exact height * * @var bool */ - private $_exactHeight = false; + private $exactHeight = false; /** * Create a new row style @@ -50,6 +50,9 @@ class Row */ public function setStyleValue($key, $value) { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } $this->$key = $value; } @@ -64,7 +67,7 @@ class Row if (!is_bool($pValue)) { $pValue = false; } - $this->_tblHeader = $pValue; + $this->tblHeader = $pValue; return $this; } @@ -75,7 +78,7 @@ class Row */ public function getTblHeader() { - return $this->_tblHeader; + return $this->tblHeader; } /** @@ -89,7 +92,7 @@ class Row if (!is_bool($pValue)) { $pValue = false; } - $this->_cantSplit = $pValue; + $this->cantSplit = $pValue; return $this; } @@ -100,7 +103,7 @@ class Row */ public function getCantSplit() { - return $this->_cantSplit; + return $this->cantSplit; } /** @@ -114,7 +117,7 @@ class Row if (!is_bool($pValue)) { $pValue = false; } - $this->_exactHeight = $pValue; + $this->exactHeight = $pValue; return $this; } @@ -125,6 +128,6 @@ class Row */ public function getExactHeight() { - return $this->_exactHeight; + return $this->exactHeight; } } diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index f1aa10bc..f49d9847 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -24,21 +24,21 @@ class TOC * * @var string */ - private $_tabLeader; + private $tabLeader; /** * Tab Position * * @var int */ - private $_tabPos; + private $tabPos; /** * Indent * * @var int */ - private $_indent; + private $indent; /** @@ -46,9 +46,9 @@ class TOC */ public function __construct() { - $this->_tabPos = 9062; - $this->_tabLeader = self::TABLEADER_DOT; - $this->_indent = 200; + $this->tabPos = 9062; + $this->tabLeader = self::TABLEADER_DOT; + $this->indent = 200; } /** @@ -58,7 +58,7 @@ class TOC */ public function getTabPos() { - return $this->_tabPos; + return $this->tabPos; } /** @@ -68,7 +68,7 @@ class TOC */ public function setTabPos($pValue) { - $this->_tabPos = $pValue; + $this->tabPos = $pValue; } /** @@ -78,7 +78,7 @@ class TOC */ public function getTabLeader() { - return $this->_tabLeader; + return $this->tabLeader; } /** @@ -88,7 +88,7 @@ class TOC */ public function setTabLeader($pValue = self::TABLEADER_DOT) { - $this->_tabLeader = $pValue; + $this->tabLeader = $pValue; } /** @@ -98,7 +98,7 @@ class TOC */ public function getIndent() { - return $this->_indent; + return $this->indent; } /** @@ -108,7 +108,7 @@ class TOC */ public function setIndent($pValue) { - $this->_indent = $pValue; + $this->indent = $pValue; } /** diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 8524143b..59757ea8 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -21,21 +21,21 @@ class Tab * * @var string */ - private $_val; + private $val; /** * Tab Leader Character * * @var string */ - private $_leader; + private $leader; /** * Tab Stop Position * * @var int */ - private $_position; + private $position; /** * Tab Stop Type @@ -43,7 +43,7 @@ class Tab * @var array * @link http://www.schemacentral.com/sc/ooxml/a-w_val-26.html Tab Stop Type */ - private static $_possibleStopTypes = array( + private static $possibleStopTypes = array( 'clear', // No Tab Stop 'left', // Left Tab Stop 'center', // Center Tab Stop @@ -59,7 +59,7 @@ class Tab * @var array * @link http://www.schemacentral.com/sc/ooxml/a-w_leader-1.html Tab Leader Character */ - private static $_possibleLeaders = array( + private static $possibleLeaders = array( 'none', // No tab stop leader 'dot', // Dotted leader line 'hyphen', // Dashed tab stop leader line @@ -80,13 +80,13 @@ class Tab public function __construct($val = null, $position = 0, $leader = null) { // Default to clear if the stop type is not matched - $this->_val = (self::isStopType($val)) ? $val : 'clear'; + $this->val = (self::isStopType($val)) ? $val : 'clear'; // Default to 0 if the position is non-numeric - $this->_position = (is_numeric($position)) ? intval($position) : 0; + $this->position = (is_numeric($position)) ? intval($position) : 0; // Default to NULL if no tab leader - $this->_leader = (self::isLeaderType($leader)) ? $leader : null; + $this->leader = (self::isLeaderType($leader)) ? $leader : null; } /** @@ -98,11 +98,11 @@ class Tab { if (isset($xmlWriter)) { $xmlWriter->startElement("w:tab"); - $xmlWriter->writeAttribute("w:val", $this->_val); - if (!is_null($this->_leader)) { - $xmlWriter->writeAttribute("w:leader", $this->_leader); + $xmlWriter->writeAttribute("w:val", $this->val); + if (!is_null($this->leader)) { + $xmlWriter->writeAttribute("w:leader", $this->leader); } - $xmlWriter->writeAttribute("w:pos", $this->_position); + $xmlWriter->writeAttribute("w:pos", $this->position); $xmlWriter->endElement(); } } @@ -115,7 +115,7 @@ class Tab */ private static function isStopType($attribute) { - return in_array($attribute, self::$_possibleStopTypes); + return in_array($attribute, self::$possibleStopTypes); } /** @@ -126,6 +126,6 @@ class Tab */ private static function isLeaderType($attribute) { - return in_array($attribute, self::$_possibleLeaders); + return in_array($attribute, self::$possibleLeaders); } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index bf744a3e..178c2854 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -19,126 +19,126 @@ class Table * * @var \PhpOffice\PhpWord\Style\Table */ - private $_firstRow = null; + private $firstRow = null; /** * Cell margin top * * @var int */ - private $_cellMarginTop = null; + private $cellMarginTop = null; /** * Cell margin left * * @var int */ - private $_cellMarginLeft = null; + private $cellMarginLeft = null; /** * Cell margin right * * @var int */ - private $_cellMarginRight = null; + private $cellMarginRight = null; /** * Cell margin bottom * * @var int */ - private $_cellMarginBottom = null; + private $cellMarginBottom = null; /** * Background color * * @var string */ - private $_bgColor; + private $bgColor; /** * Border size top * * @var int */ - private $_borderTopSize; + private $borderTopSize; /** * Border color * * @var string top */ - private $_borderTopColor; + private $borderTopColor; /** * Border size left * * @var int */ - private $_borderLeftSize; + private $borderLeftSize; /** * Border color left * * @var string */ - private $_borderLeftColor; + private $borderLeftColor; /** * Border size right * * @var int */ - private $_borderRightSize; + private $borderRightSize; /** * Border color right * * @var string */ - private $_borderRightColor; + private $borderRightColor; /** * Border size bottom * * @var int */ - private $_borderBottomSize; + private $borderBottomSize; /** * Border color bottom * * @var string */ - private $_borderBottomColor; + private $borderBottomColor; /** * Border size inside horizontal * * @var int */ - private $_borderInsideHSize; + private $borderInsideHSize; /** * Border color inside horizontal * * @var string */ - private $_borderInsideHColor; + private $borderInsideHColor; /** * Border size inside vertical * * @var int */ - private $_borderInsideVSize; + private $borderInsideVSize; /** * Border color inside vertical * * @var string */ - private $_borderInsideVColor; + private $borderInsideVColor; /** * Create new table style @@ -149,30 +149,29 @@ class Table public function __construct($styleTable = null, $styleFirstRow = null) { if (!is_null($styleFirstRow) && is_array($styleFirstRow)) { - $this->_firstRow = clone $this; + $this->firstRow = clone $this; - unset($this->_firstRow->_firstRow); - unset($this->_firstRow->_cellMarginBottom); - unset($this->_firstRow->_cellMarginTop); - unset($this->_firstRow->_cellMarginLeft); - unset($this->_firstRow->_cellMarginRight); - unset($this->_firstRow->_borderInsideVColor); - unset($this->_firstRow->_borderInsideVSize); - unset($this->_firstRow->_borderInsideHColor); - unset($this->_firstRow->_borderInsideHSize); + unset($this->firstRow->firstRow); + unset($this->firstRow->cellMarginBottom); + unset($this->firstRow->cellMarginTop); + unset($this->firstRow->cellMarginLeft); + unset($this->firstRow->cellMarginRight); + unset($this->firstRow->borderInsideVColor); + unset($this->firstRow->borderInsideVSize); + unset($this->firstRow->borderInsideHColor); + unset($this->firstRow->borderInsideHSize); foreach ($styleFirstRow as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } - - $this->_firstRow->setStyleValue($key, $value); + $this->firstRow->setStyleValue($key, $value); } } if (!is_null($styleTable) && is_array($styleTable)) { foreach ($styleTable as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } $this->setStyleValue($key, $value); } @@ -187,11 +186,14 @@ class Table */ public function setStyleValue($key, $value) { - if ($key == '_borderSize') { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + if ($key == 'borderSize') { $this->setBorderSize($value); - } elseif ($key == '_borderColor') { + } elseif ($key == 'borderColor') { $this->setBorderColor($value); - } elseif ($key == '_cellMargin') { + } elseif ($key == 'cellMargin') { $this->setCellMargin($value); } else { $this->$key = $value; @@ -205,7 +207,7 @@ class Table */ public function getFirstRow() { - return $this->_firstRow; + return $this->firstRow; } /** @@ -215,7 +217,7 @@ class Table */ public function getBgColor() { - return $this->_bgColor; + return $this->bgColor; } /** @@ -226,7 +228,7 @@ class Table */ public function setBgColor($pValue = null) { - $this->_bgColor = $pValue; + $this->bgColor = $pValue; } /** @@ -236,12 +238,12 @@ class Table */ public function setBorderSize($pValue = null) { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; - $this->_borderInsideHSize = $pValue; - $this->_borderInsideVSize = $pValue; + $this->borderTopSize = $pValue; + $this->borderLeftSize = $pValue; + $this->borderRightSize = $pValue; + $this->borderBottomSize = $pValue; + $this->borderInsideHSize = $pValue; + $this->borderInsideVSize = $pValue; } /** @@ -267,12 +269,12 @@ class Table */ public function setBorderColor($pValue = null) { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; - $this->_borderInsideHColor = $pValue; - $this->_borderInsideVColor = $pValue; + $this->borderTopColor = $pValue; + $this->borderLeftColor = $pValue; + $this->borderRightColor = $pValue; + $this->borderBottomColor = $pValue; + $this->borderInsideHColor = $pValue; + $this->borderInsideVColor = $pValue; } /** @@ -299,7 +301,7 @@ class Table */ public function setBorderTopSize($pValue = null) { - $this->_borderTopSize = $pValue; + $this->borderTopSize = $pValue; } /** @@ -309,7 +311,7 @@ class Table */ public function getBorderTopSize() { - return $this->_borderTopSize; + return $this->borderTopSize; } /** @@ -319,7 +321,7 @@ class Table */ public function setBorderTopColor($pValue = null) { - $this->_borderTopColor = $pValue; + $this->borderTopColor = $pValue; } /** @@ -329,7 +331,7 @@ class Table */ public function getBorderTopColor() { - return $this->_borderTopColor; + return $this->borderTopColor; } /** @@ -339,7 +341,7 @@ class Table */ public function setBorderLeftSize($pValue = null) { - $this->_borderLeftSize = $pValue; + $this->borderLeftSize = $pValue; } /** @@ -349,7 +351,7 @@ class Table */ public function getBorderLeftSize() { - return $this->_borderLeftSize; + return $this->borderLeftSize; } /** @@ -359,7 +361,7 @@ class Table */ public function setBorderLeftColor($pValue = null) { - $this->_borderLeftColor = $pValue; + $this->borderLeftColor = $pValue; } /** @@ -369,7 +371,7 @@ class Table */ public function getBorderLeftColor() { - return $this->_borderLeftColor; + return $this->borderLeftColor; } /** @@ -379,7 +381,7 @@ class Table */ public function setBorderRightSize($pValue = null) { - $this->_borderRightSize = $pValue; + $this->borderRightSize = $pValue; } /** @@ -389,7 +391,7 @@ class Table */ public function getBorderRightSize() { - return $this->_borderRightSize; + return $this->borderRightSize; } /** @@ -399,7 +401,7 @@ class Table */ public function setBorderRightColor($pValue = null) { - $this->_borderRightColor = $pValue; + $this->borderRightColor = $pValue; } /** @@ -409,7 +411,7 @@ class Table */ public function getBorderRightColor() { - return $this->_borderRightColor; + return $this->borderRightColor; } /** @@ -419,7 +421,7 @@ class Table */ public function setBorderBottomSize($pValue = null) { - $this->_borderBottomSize = $pValue; + $this->borderBottomSize = $pValue; } /** @@ -429,7 +431,7 @@ class Table */ public function getBorderBottomSize() { - return $this->_borderBottomSize; + return $this->borderBottomSize; } /** @@ -439,7 +441,7 @@ class Table */ public function setBorderBottomColor($pValue = null) { - $this->_borderBottomColor = $pValue; + $this->borderBottomColor = $pValue; } /** @@ -449,7 +451,7 @@ class Table */ public function getBorderBottomColor() { - return $this->_borderBottomColor; + return $this->borderBottomColor; } /** @@ -459,7 +461,7 @@ class Table */ public function setBorderInsideHColor($pValue = null) { - $this->_borderInsideHColor = $pValue; + $this->borderInsideHColor = $pValue; } /** @@ -469,7 +471,7 @@ class Table */ public function getBorderInsideHColor() { - return (isset($this->_borderInsideHColor)) ? $this->_borderInsideHColor : null; + return (isset($this->borderInsideHColor)) ? $this->borderInsideHColor : null; } /** @@ -479,7 +481,7 @@ class Table */ public function setBorderInsideVColor($pValue = null) { - $this->_borderInsideVColor = $pValue; + $this->borderInsideVColor = $pValue; } /** @@ -489,7 +491,7 @@ class Table */ public function getBorderInsideVColor() { - return (isset($this->_borderInsideVColor)) ? $this->_borderInsideVColor : null; + return (isset($this->borderInsideVColor)) ? $this->borderInsideVColor : null; } /** @@ -499,7 +501,7 @@ class Table */ public function setBorderInsideHSize($pValue = null) { - $this->_borderInsideHSize = $pValue; + $this->borderInsideHSize = $pValue; } /** @@ -509,7 +511,7 @@ class Table */ public function getBorderInsideHSize() { - return (isset($this->_borderInsideHSize)) ? $this->_borderInsideHSize : null; + return (isset($this->borderInsideHSize)) ? $this->borderInsideHSize : null; } /** @@ -519,7 +521,7 @@ class Table */ public function setBorderInsideVSize($pValue = null) { - $this->_borderInsideVSize = $pValue; + $this->borderInsideVSize = $pValue; } /** @@ -529,7 +531,7 @@ class Table */ public function getBorderInsideVSize() { - return (isset($this->_borderInsideVSize)) ? $this->_borderInsideVSize : null; + return (isset($this->borderInsideVSize)) ? $this->borderInsideVSize : null; } /** @@ -539,7 +541,7 @@ class Table */ public function setCellMarginTop($pValue = null) { - $this->_cellMarginTop = $pValue; + $this->cellMarginTop = $pValue; } /** @@ -549,7 +551,7 @@ class Table */ public function getCellMarginTop() { - return $this->_cellMarginTop; + return $this->cellMarginTop; } /** @@ -559,7 +561,7 @@ class Table */ public function setCellMarginLeft($pValue = null) { - $this->_cellMarginLeft = $pValue; + $this->cellMarginLeft = $pValue; } /** @@ -569,7 +571,7 @@ class Table */ public function getCellMarginLeft() { - return $this->_cellMarginLeft; + return $this->cellMarginLeft; } /** @@ -579,7 +581,7 @@ class Table */ public function setCellMarginRight($pValue = null) { - $this->_cellMarginRight = $pValue; + $this->cellMarginRight = $pValue; } /** @@ -589,7 +591,7 @@ class Table */ public function getCellMarginRight() { - return $this->_cellMarginRight; + return $this->cellMarginRight; } /** @@ -599,7 +601,7 @@ class Table */ public function setCellMarginBottom($pValue = null) { - $this->_cellMarginBottom = $pValue; + $this->cellMarginBottom = $pValue; } /** @@ -609,7 +611,7 @@ class Table */ public function getCellMarginBottom() { - return $this->_cellMarginBottom; + return $this->cellMarginBottom; } /** @@ -619,10 +621,10 @@ class Table */ public function setCellMargin($pValue = null) { - $this->_cellMarginTop = $pValue; - $this->_cellMarginLeft = $pValue; - $this->_cellMarginRight = $pValue; - $this->_cellMarginBottom = $pValue; + $this->cellMarginTop = $pValue; + $this->cellMarginLeft = $pValue; + $this->cellMarginRight = $pValue; + $this->cellMarginBottom = $pValue; } /** @@ -632,6 +634,6 @@ class Table */ public function getCellMargin() { - return array($this->_cellMarginTop, $this->_cellMarginLeft, $this->_cellMarginRight, $this->_cellMarginBottom); + return array($this->cellMarginTop, $this->cellMarginLeft, $this->cellMarginRight, $this->cellMarginBottom); } } diff --git a/src/PhpWord/Style/Tabs.php b/src/PhpWord/Style/Tabs.php index 343a2b35..497e09f1 100755 --- a/src/PhpWord/Style/Tabs.php +++ b/src/PhpWord/Style/Tabs.php @@ -21,7 +21,7 @@ class Tabs * * @var array */ - private $_tabs; + private $tabs; /** * Create new tab collection style @@ -30,7 +30,7 @@ class Tabs */ public function __construct(array $tabs) { - $this->_tabs = $tabs; + $this->tabs = $tabs; } /** @@ -42,7 +42,7 @@ class Tabs { if (isset($xmlWriter)) { $xmlWriter->startElement("w:tabs"); - foreach ($this->_tabs as &$tab) { + foreach ($this->tabs as &$tab) { $tab->toXml($xmlWriter); } $xmlWriter->endElement(); diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index 2793d2f0..cb3ad02f 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -82,8 +82,8 @@ class TOC if (!is_null($styleTOC) && is_array($styleTOC)) { foreach ($styleTOC as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } self::$TOCStyle->setStyleValue($key, $value); } @@ -93,8 +93,8 @@ class TOC if (is_array($styleFont)) { self::$fontStyle = new Font(); foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); } self::$fontStyle->setStyleValue($key, $value); } diff --git a/tests/PhpWord/Tests/Style/CellTest.php b/tests/PhpWord/Tests/Style/CellTest.php index bfe97282..9bf5a917 100644 --- a/tests/PhpWord/Tests/Style/CellTest.php +++ b/tests/PhpWord/Tests/Style/CellTest.php @@ -61,10 +61,10 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($default, $object->getDefaultBorderColor()); - $object->setStyleValue('_defaultBorderColor', $value); + $object->setStyleValue('defaultBorderColor', $value); $this->assertEquals($value, $object->getDefaultBorderColor()); - $object->setStyleValue('_borderColor', $value); + $object->setStyleValue('borderColor', $value); $expected = array($value, $value, $value, $value); $this->assertEquals($expected, $object->getBorderColor()); } @@ -78,7 +78,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $value = 120; $expected = array($value, $value, $value, $value); - $object->setStyleValue('_borderSize', $value); + $object->setStyleValue('borderSize', $value); $this->assertEquals($expected, $object->getBorderSize()); } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index d26b97fe..9185d646 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -62,9 +62,9 @@ class FontTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $default) { $get = "get{$key}"; - $object->setStyleValue("_$key", null); + $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("_$key", ''); + $object->setStyleValue("$key", ''); $this->assertEquals($default, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index 2d96201d..b35c8cb2 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -58,7 +58,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase ); foreach ($properties as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_{$key}", $value); + $object->setStyleValue("{$key}", $value); $this->assertEquals($value, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/ListItemTest.php b/tests/PhpWord/Tests/Style/ListItemTest.php index ed9c9048..0fb67da3 100644 --- a/tests/PhpWord/Tests/Style/ListItemTest.php +++ b/tests/PhpWord/Tests/Style/ListItemTest.php @@ -38,7 +38,7 @@ class ListItemTest extends \PHPUnit_Framework_TestCase $object = new ListItem(); $value = ListItem::TYPE_ALPHANUM; - $object->setStyleValue('_listType', $value); + $object->setStyleValue('listType', $value); $this->assertEquals($value, $object->getListType()); } diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 10a74dae..413eb149 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -45,9 +45,9 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $default) { $get = "get{$key}"; - $object->setStyleValue("_$key", null); + $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("_$key", ''); + $object->setStyleValue("$key", ''); $this->assertEquals($default, $object->$get()); } } @@ -75,7 +75,7 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_$key", $value); + $object->setStyleValue("$key", $value); if ($key == 'align') { if ($value == 'justify') { $value = 'both'; diff --git a/tests/PhpWord/Tests/Style/RowTest.php b/tests/PhpWord/Tests/Style/RowTest.php index fefb7b0a..ad193f80 100644 --- a/tests/PhpWord/Tests/Style/RowTest.php +++ b/tests/PhpWord/Tests/Style/RowTest.php @@ -42,7 +42,7 @@ class RowTest extends \PHPUnit_Framework_TestCase // setStyleValue $value = !$value; $expected = $value ? 1 : 0; - $object->setStyleValue("_{$key}", $value); + $object->setStyleValue("{$key}", $value); $this->assertEquals($expected, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/TOCTest.php b/tests/PhpWord/Tests/Style/TOCTest.php index 34c86186..2c10de8d 100644 --- a/tests/PhpWord/Tests/Style/TOCTest.php +++ b/tests/PhpWord/Tests/Style/TOCTest.php @@ -39,7 +39,7 @@ class TOCTest extends \PHPUnit_Framework_TestCase $this->assertEquals($value, $object->$get()); // setStyleValue - $object->setStyleValue("_{$key}", null); + $object->setStyleValue("{$key}", null); $this->assertEquals(null, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index a193f43d..e5c3ab66 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -143,9 +143,9 @@ class TableTest extends \PHPUnit_Framework_TestCase public function testSetStyleValue() { $object = new Table(); - $object->setStyleValue('_borderSize', 120); - $object->setStyleValue('_cellMargin', 240); - $object->setStyleValue('_borderColor', '999999'); + $object->setStyleValue('borderSize', 120); + $object->setStyleValue('cellMargin', 240); + $object->setStyleValue('borderColor', '999999'); $this->assertEquals( array(120, 120, 120, 120, 120, 120), From d1d1e6b4df8c7a60b31781baafd30efa22c8f8fc Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Mon, 7 Apr 2014 18:06:42 +0700 Subject: [PATCH 064/146] Reader: Ability to read tables, links, preserve text, and text break --- src/PhpWord/Container/Section.php | 3 + src/PhpWord/Container/Settings.php | 5 +- src/PhpWord/Reader/Word2007.php | 756 ++++++++++++++++++++--------- src/PhpWord/Shared/XMLReader.php | 163 +++++++ src/PhpWord/Style.php | 10 +- 5 files changed, 694 insertions(+), 243 deletions(-) create mode 100644 src/PhpWord/Shared/XMLReader.php diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Container/Section.php index dae4f26c..0b55f991 100644 --- a/src/PhpWord/Container/Section.php +++ b/src/PhpWord/Container/Section.php @@ -66,6 +66,9 @@ class Section extends Container { if (!is_null($settings) && is_array($settings)) { foreach ($settings as $key => $value) { + if (is_null($value)) { + continue; + } if (substr($key, 0, 1) == '_') { $key = substr($key, 1); } diff --git a/src/PhpWord/Container/Settings.php b/src/PhpWord/Container/Settings.php index 762d45c3..40c20d8c 100644 --- a/src/PhpWord/Container/Settings.php +++ b/src/PhpWord/Container/Settings.php @@ -229,7 +229,10 @@ class Settings } elseif ($key == 'borderColor') { $this->setBorderColor($value); } else { - $this->$key = $value; + $method = 'set' . $key; + if (method_exists($this, $method)) { + $this->$method($value); + } } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 2cdb7f9a..9cc4f330 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -13,31 +13,54 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\DocumentProperties; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLReader; +use PhpOffice\PhpWord\Container\Section; /** * Reader for Word2007 */ class Word2007 extends Reader implements IReader { + /** + * PhpWord object + * + * @var PhpWord + */ + private $phpWord; + + /** + * Part relationships + * + * @var array + */ + private $partRels = array('document' => array(), 'footnotes' => array()); + + /** + * Current active part document|footnotes|headerx|footerx + * + * @var string + */ + private $activePart = 'document'; + /** * Can the current IReader read the file? * - * @param string $pFilename + * @param string $fileName * @return bool - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws Exception */ - public function canRead($pFilename) + public function canRead($fileName) { // Check if file exists - if (!file_exists($pFilename)) { - throw new Exception("Could not open {$pFilename} for reading! File does not exist."); + if (!file_exists($fileName)) { + throw new Exception("Could not open {$fileName} for reading! File does not exist."); } $return = false; // Load file $zipClass = Settings::getZipClass(); $zip = new $zipClass(); - if ($zip->open($pFilename) === true) { + if ($zip->open($fileName) === true) { // check if it is an OOXML archive $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); if ($rels !== false) { @@ -91,21 +114,24 @@ class Word2007 extends Reader implements IReader /** * Loads PhpWord from file * - * @param string $pFilename - * @return \PhpOffice\PhpWord\PhpWord|null + * @param string $fileName + * @return PhpWord|null */ - public function load($pFilename) + public function load($fileName) { // Check if file exists and can be read - if (!$this->canRead($pFilename)) { + if (!$this->canRead($fileName)) { return null; } // Initialisations - $word = new PhpWord(); + $this->phpWord = new PhpWord(); $zipClass = Settings::getZipClass(); $zip = new $zipClass(); - $zip->open($pFilename); + $zip->open($fileName); + + // Read document relationships + $this->readPartRels($fileName, 'document'); // Read properties and documents $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); @@ -118,7 +144,7 @@ class Word2007 extends Reader implements IReader $xmlCore->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/"); $xmlCore->registerXPathNamespace("dcterms", "http://purl.org/dc/terms/"); $xmlCore->registerXPathNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); - $docProps = $word->getDocumentProperties(); + $docProps = $this->phpWord->getDocumentProperties(); $docProps->setCreator((string)self::arrayItem($xmlCore->xpath("dc:creator"))); $docProps->setLastModifiedBy((string)self::arrayItem($xmlCore->xpath("cp:lastModifiedBy"))); $docProps->setCreated(strtotime(self::arrayItem($xmlCore->xpath("dcterms:created")))); @@ -134,7 +160,7 @@ class Word2007 extends Reader implements IReader case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties": $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); if (is_object($xmlCore)) { - $docProps = $word->getDocumentProperties(); + $docProps = $this->phpWord->getDocumentProperties(); if (isset($xmlCore->Company)) { $docProps->setCompany((string)$xmlCore->Company); } @@ -147,7 +173,7 @@ class Word2007 extends Reader implements IReader case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties": $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); if (is_object($xmlCore)) { - $docProps = $word->getDocumentProperties(); + $docProps = $this->phpWord->getDocumentProperties(); foreach ($xmlCore as $xmlProperty) { $cellDataOfficeAttributes = $xmlProperty->attributes(); if (isset($cellDataOfficeAttributes['name'])) { @@ -162,266 +188,520 @@ class Word2007 extends Reader implements IReader } } break; - // Document - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": - $dir = dirname($rel["Target"]); - $archive = "$dir/_rels/" . basename($rel["Target"]) . ".rels"; - $relsDoc = simplexml_load_string($this->getFromZipArchive($zip, $archive)); - $relsDoc->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships"); - $xpath = self::arrayItem( - $relsDoc->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']") - ); - $xmlDoc = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}", true)); - if (is_object($xmlDoc)) { - $section = $word->addSection(); - - foreach ($xmlDoc->body->children() as $elm) { - $elmName = $elm->getName(); - if ($elmName == 'p') { // Paragraph/section - // Create new section if section setting found - if ($elm->pPr->sectPr) { - $section->setSettings($this->loadSectionSettings($elm->pPr)); - $section = $word->addSection(); - continue; - } - // Has w:r? It's either text or textrun - if ($elm->r) { - // w:r = 1? It's a plain paragraph - if (count($elm->r) == 1) { - $section->addText( - $elm->r->t, - $this->loadFontStyle($elm->r) - ); - // w:r more than 1? It's a textrun - } else { - $textRun = $section->addTextRun(); - foreach ($elm->r as $r) { - $textRun->addText( - $r->t, - $this->loadFontStyle($r) - ); - } - } - // No, it's a textbreak - } else { - $section->addTextBreak(); - } - } elseif ($elmName == 'sectPr') { - // Last section setting - $section->setSettings($this->loadSectionSettings($xmlDoc->body)); - } - } - } - break; } } - // Read styles - $docRels = simplexml_load_string($this->getFromZipArchive($zip, "word/_rels/document.xml.rels")); - foreach ($docRels->Relationship as $rel) { - switch ($rel["Type"]) { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles": - $xmlStyle = simplexml_load_string($this->getFromZipArchive($zip, "word/{$rel['Target']}", true)); - if (is_object($xmlStyle)) { - foreach ($xmlStyle->children() as $elm) { - if ($elm->getName() != 'style') { - continue; - } - $pStyle = null; - $fStyle = null; - $hasParagraphStyle = isset($elm->pPr); - $hasFontStyle = isset($elm->rPr); - $styleName = (string)$elm->name['val']; - if ($hasParagraphStyle) { - $pStyle = $this->loadParagraphStyle($elm); - if (is_array($pStyle) && !$hasFontStyle) { - $word->addParagraphStyle($styleName, $pStyle); - } - } - if ($hasFontStyle) { - $fStyle = $this->loadFontStyle($elm); - $word->addFontStyle($styleName, $fStyle, $pStyle); - } - } - } - break; + // Read document + $this->readDocument($fileName, 'word/document.xml'); + + // Read document relationships + foreach ($this->partRels['document'] as $rId => $rel) { + if ($rel['type'] == 'styles') { + $this->readStyles($fileName, 'word/' . $rel['target']); } } $zip->close(); - return $word; + return $this->phpWord; } /** - * Load section settings from SimpleXMLElement + * Read _rels/$partName.xml.rels * - * @param \SimpleXMLElement $elm - * @return array|string|null - * - * @todo Implement gutter + * @param string $fileName + * @param string $partName document|footnotes|headerx|footerx */ - private function loadSectionSettings($elm) + private function readPartRels($fileName, $partName) { - if ($xml = $elm->sectPr) { - $setting = array(); - if ($xml->type) { - $setting['breakType'] = (string)$xml->type['val']; + $relPrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; + $xmlReader = new XMLReader(); + $response = $xmlReader->getDomFromZip($fileName, "word/_rels/{$partName}.xml.rels"); + if ($response) { + $rels = $xmlReader->getElements('*'); + foreach ($rels as $rel) { + $this->partRels[$partName][$rel->getAttribute('Id')] = array( + 'type' => str_replace($relPrefix, '', $rel->getAttribute('Type')), + 'target' => $rel->getAttribute('Target'), + ); } - if ($xml->pgSz) { - if (isset($xml->pgSz['w'])) { - $setting['pageSizeW'] = (int)$xml->pgSz['w']; - } - if (isset($xml->pgSz['h'])) { - $setting['pageSizeH'] = (int)$xml->pgSz['h']; - } - if (isset($xml->pgSz['orient'])) { - $setting['orientation'] = (string)$xml->pgSz['orient']; - } - } - if ($xml->pgMar) { - if (isset($xml->pgMar['top'])) { - $setting['topMargin'] = (int)$xml->pgMar['top']; - } - if (isset($xml->pgMar['left'])) { - $setting['leftMargin'] = (int)$xml->pgMar['left']; - } - if (isset($xml->pgMar['bottom'])) { - $setting['bottomMargin'] = (int)$xml->pgMar['bottom']; - } - if (isset($xml->pgMar['right'])) { - $setting['rightMargin'] = (int)$xml->pgMar['right']; - } - if (isset($xml->pgMar['header'])) { - $setting['headerHeight'] = (int)$xml->pgMar['header']; - } - if (isset($xml->pgMar['footer'])) { - $setting['footerHeight'] = (int)$xml->pgMar['footer']; - } - if (isset($xml->pgMar['gutter'])) { - // $setting['gutter'] = (int)$xml->pgMar['gutter']; - } - } - if ($xml->cols) { - if (isset($xml->cols['num'])) { - $setting['colsNum'] = (int)$xml->cols['num']; - } - if (isset($xml->cols['space'])) { - $setting['colsSpace'] = (int)$xml->cols['space']; - } - } - return $setting; } - return null; } /** - * Load paragraph style from SimpleXMLElement + * Read styles.xml * - * @param \SimpleXMLElement $elm - * @return array|string|null + * @param string $fileName + * @param string $xmlFile */ - private function loadParagraphStyle($elm) + private function readStyles($fileName, $xmlFile) { - if ($xml = $elm->pPr) { - if ($xml->pStyle) { - return (string)$xml->pStyle['val']; - } - $style = array(); - if ($xml->jc) { - $style['align'] = (string)$xml->jc['val']; - } - if ($xml->ind) { - if (isset($xml->ind->left)) { - $style['indent'] = (int)$xml->ind->left; + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($fileName, $xmlFile); + + $nodes = $xmlReader->getElements('w:style'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $type = $xmlReader->getAttribute($node, 'w:type'); + $name = $xmlReader->getAttribute($node, 'w:styleId'); + if (is_null($name)) { + $name = $xmlReader->getAttribute('w:name', 'w:val', $node); } - if (isset($xml->ind->hanging)) { - $style['hanging'] = (int)$xml->ind->hanging; - } - if (isset($xml->ind->line)) { - $style['spacing'] = (int)$xml->ind->line; + $default = ($xmlReader->getAttribute($node, 'w:default') == 1); + if ($type == 'paragraph') { + $pStyle = $this->readWpPr($xmlReader, $node); + $fStyle = $this->readWrPr($xmlReader, $node); + if (empty($fStyle)) { + $this->phpWord->addParagraphStyle($name, $pStyle); + } else { + $this->phpWord->addFontStyle($name, $fStyle, $pStyle); + } + } elseif ($type == 'character') { + $fStyle = $this->readWrPr($xmlReader, $node); + if (!empty($fStyle)) { + $this->phpWord->addFontStyle($name, $fStyle); + } + } elseif ($type == 'table') { + $tStyle = $this->readWtblPr($xmlReader, $node); + if (!empty($tStyle)) { + $this->phpWord->addTableStyle($name, $tStyle); + } } } - if ($xml->spacing) { - if (isset($xml->spacing['after'])) { - $style['spaceAfter'] = (int)$xml->spacing['after']; - } - if (isset($xml->spacing['before'])) { - $style['spaceBefore'] = (int)$xml->spacing['before']; - } - if (isset($xml->spacing['line'])) { - $style['spacing'] = (int)$xml->spacing['line']; - } - } - if ($xml->basedOn) { - $style['basedOn'] = (string)$xml->basedOn['val']; - } - if ($xml->next) { - $style['next'] = (string)$xml->next['val']; - } - if ($xml->widowControl) { - $style['widowControl'] = false; - } - if ($xml->keepNext) { - $style['keepNext'] = true; - } - if ($xml->keepLines) { - $style['keepLines'] = true; - } - if ($xml->pageBreakBefore) { - $style['pageBreakBefore'] = true; - } - return $style; } - return null; } /** - * Load font style from SimpleXMLElement + * Read document.xml * - * @param \SimpleXMLElement $elm - * @return array|string|null + * @param string $fileName + * @param string $xmlFile */ - private function loadFontStyle($elm) + private function readDocument($fileName, $xmlFile) { - if ($xml = $elm->rPr) { - if ($xml->rStyle) { - return (string)$xml->rStyle['val']; + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($fileName, $xmlFile); + + $nodes = $xmlReader->getElements('w:body/*'); + if ($nodes->length > 0) { + $section = $this->phpWord->addSection(); + foreach ($nodes as $node) { + if ($node->nodeName == 'w:p') { // Paragraph + if ($xmlReader->getAttribute('w:r/w:br', 'w:type', $node) == 'page') { + $section->addPageBreak(); // PageBreak + } else { + $this->readWp($xmlReader, $node, $section); + } + // Section properties + if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { + $settingsNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); + $settings = $this->readWsectPr($xmlReader, $settingsNode); + $section->setSettings($settings); + $this->readHeaderFooter($fileName, $settings, $section); + $section = $this->phpWord->addSection(); + } + } elseif ($node->nodeName == 'w:tbl') { // Table + $this->readWtbl($xmlReader, $node, $section); + } elseif ($node->nodeName == 'w:sectPr') { // Last section + $settings = $this->readWsectPr($xmlReader, $node); + $section->setSettings($settings); + $this->readHeaderFooter($fileName, $settings, $section); + } } - $style = array(); - if ($xml->rFonts) { - $style['name'] = (string)$xml->rFonts['ascii']; + } + } + + /** + * Read header footer + * + * @param string $fileName + * @param array $settings + * @param Section $section + */ + private function readHeaderFooter($fileName, $settings, &$section) + { + if (is_array($settings) && array_key_exists('headerFooter', $settings)) { + foreach ($settings['headerFooter'] as $rId => $headerFooter) { + if (array_key_exists($rId, $this->partRels['document'])) { + $target = $this->partRels['document'][$rId]['target']; + $xmlFile = 'word/' . $target; + $method = 'add' . $headerFooter['method']; + $type = $headerFooter['type']; + $object = $section->$method($type); + + $this->activePart = str_replace('.xml', '', $target); + $this->readPartRels($fileName, $this->activePart); + + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($fileName, $xmlFile); + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + if ($node->nodeName == 'w:p') { // Paragraph + $this->readWp($xmlReader, $node, $object); + } elseif ($node->nodeName == 'w:tbl') { // Table + $this->readWtbl($xmlReader, $node, $object); + } + } + } + } } - if ($xml->sz) { - $style['size'] = (int)$xml->sz['val'] / 2; - } - if ($xml->color) { - $style['color'] = (string)$xml->color['val']; - } - if ($xml->b) { - $style['bold'] = true; - } - if ($xml->i) { - $style['italic'] = true; - } - if ($xml->u) { - $style['underline'] = (string)$xml->u['val']; - } - if ($xml->strike) { - $style['strikethrough'] = true; - } - if ($xml->highlight) { - $style['fgColor'] = (string)$xml->highlight['val']; - } - if ($xml->vertAlign) { - if ($xml->vertAlign['val'] == 'superscript') { - $style['superScript'] = true; + } + $this->activePart = 'document'; + } + + /** + * Read w:p + * + * @param mixed $container + * @todo Get font style for preserve text + */ + private function readWp(XMLReader $xmlReader, \DOMNode $domNode, &$container) + { + // Paragraph style + $pStyle = null; + if ($xmlReader->elementExists('w:pPr', $domNode)) { + $pStyle = $this->readWpPr($xmlReader, $domNode); + } + + // Content + if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { // Preserve text + $textContent = ''; + $fStyle = $this->readWrPr($xmlReader, $domNode); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $instrText = $xmlReader->getValue('w:instrText', $node); + if (!is_null($instrText)) { + $textContent .= '{' . $instrText . '}'; } else { - $style['subScript'] = true; + $textContent .= $xmlReader->getValue('w:t', $node); + } + } + $container->addPreserveText($textContent, $fStyle, $pStyle); + } else { // Text and TextRun + $runCount = $xmlReader->countElements('w:r', $domNode); + $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); + $runLinkCount = $runCount + $linkCount; + if ($runLinkCount == 0) { + $container->addTextBreak(null, $pStyle); + } else { + if ($runLinkCount > 1) { + $textContainer = &$container->addTextRun($pStyle); + $pStyle = null; + } else { + $textContainer = &$container; + } + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $this->readWr($xmlReader, $node, $textContainer, $pStyle); } } - return $style; } - return null; + } + + /** + * Read w:r + * + * @param mixed $container + * @param mixed $pStyle + */ + private function readWr(XMLReader $xmlReader, \DOMNode $domNode, &$container, $pStyle = null) + { + if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { + return; + } + $fStyle = $this->readWrPr($xmlReader, $domNode); + if ($domNode->nodeName == 'w:hyperlink') { + $rId = $xmlReader->getAttribute($domNode, 'r:id'); + $textContent = $xmlReader->getValue('w:r/w:t', $domNode); + if (array_key_exists($this->activePart, $this->partRels)) { + if (array_key_exists($rId, $this->partRels[$this->activePart])) { + $linkSource = $this->partRels[$this->activePart][$rId]['target']; + } + } + $container->addLink($linkSource, $textContent, $fStyle, $pStyle); + } else { + $textContent = $xmlReader->getValue('w:t', $domNode); + $container->addText($textContent, $fStyle, $pStyle); + } + } + + /** + * Read w:tbl + * + * @param mixed $container + */ + private function readWtbl(XMLReader $xmlReader, \DOMNode $domNode, &$container) + { + // Table style + $tblStyle = null; + if ($xmlReader->elementExists('w:tblPr', $domNode)) { + $tblStyle = $this->readWtblPr($xmlReader, $domNode); + } + + $table = $container->addTable($tblStyle); + $tblNodes = $xmlReader->getElements('*', $domNode); + foreach ($tblNodes as $tblNode) { + $tblNodeName = $tblNode->nodeName; + if ($tblNode->nodeName == 'w:tblGrid') { // Column + // @todo Do something with table columns + } elseif ($tblNode->nodeName == 'w:tr') { // Row + $rowHeight = $xmlReader->getAttribute('w:trPr/w:trHeight', 'w:val', $tblNode); + $rowHRule = $xmlReader->getAttribute('w:trPr/w:trHeight', 'w:hRule', $tblNode); + $rowHRule = $rowHRule == 'exact' ? true : false; + $rowStyle = array( + 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), + 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), + 'exactHeight' => $rowHRule, + ); + + $row = $table->addRow($rowHeight, $rowStyle); + $rowNodes = $xmlReader->getElements('*', $tblNode); + foreach ($rowNodes as $rowNode) { + if ($rowNode->nodeName == 'w:trPr') { // Row style + // @todo Do something with row style + } elseif ($rowNode->nodeName == 'w:tc') { // Cell + $cellWidth = $xmlReader->getAttribute('w:tcPr/w:tcW', 'w:w', $rowNode); + $cellStyle = null; + if ($xmlReader->elementExists('w:tcPr', $rowNode)) { + $cellStyle = $this->readWtcPr( + $xmlReader, + $xmlReader->getElement('w:tcPr', $rowNode) + ); + } + + $cell = $row->addCell($cellWidth, $cellStyle); + $cellNodes = $xmlReader->getElements('*', $rowNode); + foreach ($cellNodes as $cellNode) { + if ($cellNode->nodeName == 'w:p') { // Paragraph + $this->readWp($xmlReader, $cellNode, $cell); + } + } + } + } + } + } + } + + /** + * Read w:sectPr + * + * @return array|null + */ + private function readWsectPr(XMLReader $xmlReader, \DOMNode $domNode) + { + $ret = null; + $mapping = array( + 'w:type' => 'breakType', 'w:pgSz' => 'pageSize', + 'w:pgMar' => 'pageMargin', 'w:cols' => 'columns', + 'w:headerReference' => 'header', 'w:footerReference' => 'footer', + ); + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $retKey = $mapping[$nodeName]; + if ($nodeName == 'w:type') { + $ret['breakType'] = $xmlReader->getAttribute($node, 'w:val'); + } elseif ($nodeName == 'w:pgSz') { + $ret['pageSizeW'] = $xmlReader->getAttribute($node, 'w:w'); + $ret['pageSizeH'] = $xmlReader->getAttribute($node, 'w:h'); + $ret['orientation'] = $xmlReader->getAttribute($node, 'w:orient'); + } elseif ($nodeName == 'w:pgMar') { + $ret['topMargin'] = $xmlReader->getAttribute($node, 'w:top'); + $ret['leftMargin'] = $xmlReader->getAttribute($node, 'w:left'); + $ret['bottomMargin'] = $xmlReader->getAttribute($node, 'w:bottom'); + $ret['rightMargin'] = $xmlReader->getAttribute($node, 'w:right'); + $ret['headerHeight'] = $xmlReader->getAttribute($node, 'w:header'); + $ret['footerHeight'] = $xmlReader->getAttribute($node, 'w:footer'); + $ret['gutter'] = $xmlReader->getAttribute($node, 'w:gutter'); + } elseif ($nodeName == 'w:cols') { + $ret['colsNum'] = $xmlReader->getAttribute($node, 'w:num'); + $ret['colsSpace'] = $xmlReader->getAttribute($node, 'w:space'); + } elseif (in_array($nodeName, array('w:headerReference', 'w:footerReference'))) { + $id = $xmlReader->getAttribute($node, 'r:id'); + $ret['headerFooter'][$id] = array( + 'method' => $retKey, + 'type' => $xmlReader->getAttribute($node, 'w:type'), + ); + } + } + + return $ret; + } + + /** + * Read w:pPr + * + * @return string|array|null + */ + private function readWpPr(XMLReader $xmlReader, \DOMNode $domNode) + { + $ret = null; + if ($xmlReader->elementExists('w:pPr', $domNode)) { + if ($xmlReader->elementExists('w:pPr/w:pStyle', $domNode)) { + $ret = $xmlReader->getAttribute('w:pPr/w:pStyle', 'w:val', $domNode); + } else { + $ret = array(); + $mapping = array( + 'w:jc' => 'align', 'w:ind' => 'indent', 'w:spacing' => 'spacing', + 'w:basedOn' => 'basedOn', 'w:next' => 'next', + 'w:widowControl' => 'widowControl', 'w:keepNext' => 'keepNext', + 'w:keepLines' => 'keepLines', 'w:pageBreakBefore' => 'pageBreakBefore', + ); + $nodes = $xmlReader->getElements('w:pPr/*', $domNode); + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $retKey = $mapping[$nodeName]; + if ($nodeName == 'w:ind') { + $ret['indent'] = $xmlReader->getAttribute($node, 'w:left'); + $ret['hanging'] = $xmlReader->getAttribute($node, 'w:hanging'); + } elseif ($nodeName == 'w:spacing') { + $ret['spaceAfter'] = $xmlReader->getAttribute($node, 'w:after'); + $ret['spaceBefore'] = $xmlReader->getAttribute($node, 'w:before'); + $ret['line'] = $xmlReader->getAttribute($node, 'w:line'); + } elseif (in_array($nodeName, array('w:keepNext', 'w:keepLines', 'w:pageBreakBefore'))) { + $ret[$retKey] = true; + } elseif (in_array($nodeName, array('w:widowControl'))) { + $ret[$retKey] = false; + } elseif (in_array($nodeName, array('w:jc', 'w:basedOn', 'w:next'))) { + $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + } + } + } + } + + return $ret; + } + + /** + * Read w:rPr + * + * @return string|array|null + */ + private function readWrPr(XMLReader $xmlReader, \DOMNode $domNode) + { + $ret = null; + if ($xmlReader->elementExists('w:rPr', $domNode)) { + if ($xmlReader->elementExists('w:rPr/w:rStyle', $domNode)) { + $ret = $xmlReader->getAttribute('w:rPr/w:rStyle', 'w:val', $domNode); + } else { + $ret = array(); + $mapping = array( + 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', + 'w:strike' => 'strikethrough', 'w:u' => 'underline', + 'w:highlight' => 'fgColor', 'w:sz' => 'size', + 'w:rFonts' => 'name', 'w:vertAlign' => 'superScript', + ); + $nodes = $xmlReader->getElements('w:rPr/*', $domNode); + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $retKey = $mapping[$nodeName]; + if ($nodeName == 'w:rFonts') { + $ret['name'] = $xmlReader->getAttribute($node, 'w:ascii'); + $ret['hint'] = $xmlReader->getAttribute($node, 'w:hint'); + } elseif (in_array($nodeName, array('w:b', 'w:i', 'w:strike'))) { + $ret[$retKey] = true; + } elseif (in_array($nodeName, array('w:u', 'w:highlight', 'w:color'))) { + $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + } elseif ($nodeName == 'w:sz') { + $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val') / 2; + } elseif ($nodeName == 'w:vertAlign') { + $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + if ($ret[$retKey] == 'superscript') { + $ret['superScript'] = true; + } else { + $ret['superScript'] = false; + $ret['subScript'] = true; + } + } + } + } + } + + return $ret; + } + /** + * Read w:tblPr + * + * @return string|array|null + * @todo Capture w:tblStylePr w:type="firstRow" + */ + private function readWtblPr(XMLReader $xmlReader, \DOMNode $domNode) + { + $ret = null; + $margins = array('top', 'left', 'bottom', 'right'); + $borders = $margins + array('insideH', 'insideV'); + + if ($xmlReader->elementExists('w:tblPr', $domNode)) { + if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { + $ret = $xmlReader->getAttribute('w:tblPr/w:tblStyle', 'w:val', $domNode); + } else { + $ret = array(); + $mapping = array( + 'w:tblCellMar' => 'cellMargin', 'w:tblBorders' => 'border', + ); + $nodes = $xmlReader->getElements('w:tblPr/*', $domNode); + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $retKey = $mapping[$nodeName]; + if ($nodeName == 'w:tblCellMar') { + foreach ($margins as $side) { + $ucfirstSide = ucfirst($side); + $ret["cellMargin$ucfirstSide"] = $xmlReader->getAttribute("w:$side", 'w:w', $node); + } + } elseif ($nodeName == 'w:tblBorders') { + foreach ($borders as $side) { + $ucfirstSide = ucfirst($side); + $ret["border{$ucfirstSide}Size"] = $xmlReader->getAttribute("w:$side", 'w:sz', $node); + $ret["border{$ucfirstSide}Color"] = $xmlReader->getAttribute("w:$side", 'w:color', $node); + } + } + } + } + } + + return $ret; + } + + /** + * Read w:tcPr + * + * @return array|null + */ + private function readWtcPr(XMLReader $xmlReader, \DOMNode $domNode) + { + $ret = null; + $mapping = array( + 'w:shd' => 'bgColor', + 'w:vAlign' => 'valign', 'w:textDirection' => 'textDirection', + 'w:gridSpan' => 'gridSpan', 'w:vMerge' => 'vMerge', + ); + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $retKey = $mapping[$nodeName]; + if ($nodeName == 'w:shd') { + $ret['bgColor'] = $xmlReader->getAttribute($node, 'w:fill'); + } else { + $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + } + } + + return $ret; } /** diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 00000000..15ed9da3 --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,163 @@ +open($zipFile); + if ($canOpen === false) { + throw new Exception('Cannot open archive file.'); + } + $contents = $zip->getFromName($xmlFile); + $zip->close(); + if ($contents === false) { + return false; + } else { + $this->dom = new \DOMDocument(); + $this->dom->loadXML($contents); + return $this->dom; + } + } + + /** + * Get elements + * + * @param string $path + * @return \DOMNodeList + */ + public function getElements($path, \DOMNode $context = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + return $this->xpath->query($path, $context); + } + + /** + * Get elements + * + * @param string $path + * @return \DOMNodeList + */ + public function getElement($path, \DOMNode $context = null) + { + $elements = $this->getElements($path, $context); + if ($elements->length > 0) { + return $elements->item(0); + } else { + return false; + } + } + + /** + * Get element attribute + * + * @param string|\DOMNode $path + * @param string $attribute + * @return null|string + */ + public function getAttribute($path, $attribute, \DOMNode $context = null) + { + if ($path instanceof \DOMNode) { + $return = $path->getAttribute($attribute); + } else { + $elements = $this->getElements($path, $context); + if ($elements->length > 0) { + $return = $elements->item(0)->getAttribute($attribute); + } else { + $return = ''; + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @return null|string + */ + public function getValue($path, \DOMNode $context = null) + { + $elements = $this->getElements($path, $context); + if ($elements->length > 0) { + $return = $elements->item(0)->nodeValue; + } else { + $return = ''; + } + + return ($return == '') ? null : $return; + } + + /** + * Count elements + * + * @param string $path + * @return \DOMNodeList + */ + public function countElements($path, \DOMNode $context = null) + { + $elements = $this->getElements($path, $context); + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @return \DOMNodeList + */ + public function elementExists($path, \DOMNode $context = null) + { + return $this->getElements($path, $context)->length > 0; + } +} diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index e883b9ed..ab1159ce 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -140,11 +140,13 @@ class Style private static function setStyleValues($styleName, $styleValues, $styleObject) { if (!array_key_exists($styleName, self::$styles)) { - foreach ($styleValues as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); + if (is_array($styleValues)) { + foreach ($styleValues as $key => $value) { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + $styleObject->setStyleValue($key, $value); } - $styleObject->setStyleValue($key, $value); } self::$styles[$styleName] = $styleObject; From b594e32f04b6fbacdb506a43509650baa0632e59 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 8 Apr 2014 00:03:53 +0700 Subject: [PATCH 065/146] Move container files --- .../{Container/Container.php => Element/AbstractElement.php} | 0 src/PhpWord/{Container => Element}/Footer.php | 0 src/PhpWord/{Container => Element}/Header.php | 0 src/PhpWord/{Container => Element}/Section.php | 0 src/PhpWord/{Container/Settings.php => Style/Section.php} | 0 tests/PhpWord/Tests/{Container => Element}/FooterTest.php | 0 tests/PhpWord/Tests/{Container => Element}/HeaderTest.php | 0 tests/PhpWord/Tests/{Container => Element}/SectionTest.php | 0 .../Tests/{Container/SettingsTest.php => Style/SectionTest.php} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/PhpWord/{Container/Container.php => Element/AbstractElement.php} (100%) rename src/PhpWord/{Container => Element}/Footer.php (100%) rename src/PhpWord/{Container => Element}/Header.php (100%) rename src/PhpWord/{Container => Element}/Section.php (100%) rename src/PhpWord/{Container/Settings.php => Style/Section.php} (100%) rename tests/PhpWord/Tests/{Container => Element}/FooterTest.php (100%) rename tests/PhpWord/Tests/{Container => Element}/HeaderTest.php (100%) rename tests/PhpWord/Tests/{Container => Element}/SectionTest.php (100%) rename tests/PhpWord/Tests/{Container/SettingsTest.php => Style/SectionTest.php} (100%) diff --git a/src/PhpWord/Container/Container.php b/src/PhpWord/Element/AbstractElement.php similarity index 100% rename from src/PhpWord/Container/Container.php rename to src/PhpWord/Element/AbstractElement.php diff --git a/src/PhpWord/Container/Footer.php b/src/PhpWord/Element/Footer.php similarity index 100% rename from src/PhpWord/Container/Footer.php rename to src/PhpWord/Element/Footer.php diff --git a/src/PhpWord/Container/Header.php b/src/PhpWord/Element/Header.php similarity index 100% rename from src/PhpWord/Container/Header.php rename to src/PhpWord/Element/Header.php diff --git a/src/PhpWord/Container/Section.php b/src/PhpWord/Element/Section.php similarity index 100% rename from src/PhpWord/Container/Section.php rename to src/PhpWord/Element/Section.php diff --git a/src/PhpWord/Container/Settings.php b/src/PhpWord/Style/Section.php similarity index 100% rename from src/PhpWord/Container/Settings.php rename to src/PhpWord/Style/Section.php diff --git a/tests/PhpWord/Tests/Container/FooterTest.php b/tests/PhpWord/Tests/Element/FooterTest.php similarity index 100% rename from tests/PhpWord/Tests/Container/FooterTest.php rename to tests/PhpWord/Tests/Element/FooterTest.php diff --git a/tests/PhpWord/Tests/Container/HeaderTest.php b/tests/PhpWord/Tests/Element/HeaderTest.php similarity index 100% rename from tests/PhpWord/Tests/Container/HeaderTest.php rename to tests/PhpWord/Tests/Element/HeaderTest.php diff --git a/tests/PhpWord/Tests/Container/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php similarity index 100% rename from tests/PhpWord/Tests/Container/SectionTest.php rename to tests/PhpWord/Tests/Element/SectionTest.php diff --git a/tests/PhpWord/Tests/Container/SettingsTest.php b/tests/PhpWord/Tests/Style/SectionTest.php similarity index 100% rename from tests/PhpWord/Tests/Container/SettingsTest.php rename to tests/PhpWord/Tests/Style/SectionTest.php From f1108c48e60bdd3f509683a618481e03c9866258 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 8 Apr 2014 00:23:49 +0700 Subject: [PATCH 066/146] Add Abstract- prefix and -Interface suffix for corresponding classes --- CHANGELOG.md | 16 +- src/PhpWord/Element/AbstractElement.php | 225 ++++++++++++------ src/PhpWord/Element/Cell.php | 3 +- src/PhpWord/Element/CheckBox.php | 2 +- src/PhpWord/Element/Element.php | 106 --------- src/PhpWord/Element/Footer.php | 4 +- src/PhpWord/Element/Footnote.php | 3 +- src/PhpWord/Element/Header.php | 4 +- src/PhpWord/Element/Image.php | 5 +- src/PhpWord/Element/Link.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PageBreak.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/Element/Row.php | 2 +- src/PhpWord/Element/Section.php | 18 +- src/PhpWord/Element/Table.php | 2 +- src/PhpWord/Element/Text.php | 2 +- src/PhpWord/Element/TextBreak.php | 2 +- src/PhpWord/Element/TextRun.php | 3 +- src/PhpWord/Element/Title.php | 2 +- src/PhpWord/IOFactory.php | 8 +- src/PhpWord/PhpWord.php | 4 +- .../Reader/{Reader.php => AbstractReader.php} | 6 +- .../{IReader.php => ReaderInterface.php} | 4 +- src/PhpWord/Reader/Word2007.php | 4 +- src/PhpWord/Style/Section.php | 4 +- .../Writer/{Writer.php => AbstractWriter.php} | 2 +- src/PhpWord/Writer/ODText.php | 2 +- ...{WriterPart.php => AbstractWriterPart.php} | 2 +- src/PhpWord/Writer/ODText/Content.php | 2 +- src/PhpWord/Writer/ODText/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Meta.php | 2 +- src/PhpWord/Writer/ODText/Mimetype.php | 2 +- src/PhpWord/Writer/ODText/Styles.php | 2 +- src/PhpWord/Writer/RTF.php | 2 +- src/PhpWord/Writer/Word2007.php | 4 +- ...{WriterPart.php => AbstractWriterPart.php} | 14 +- src/PhpWord/Writer/Word2007/Base.php | 8 +- src/PhpWord/Writer/Word2007/ContentTypes.php | 2 +- src/PhpWord/Writer/Word2007/DocProps.php | 2 +- src/PhpWord/Writer/Word2007/Document.php | 2 +- src/PhpWord/Writer/Word2007/Footer.php | 2 +- src/PhpWord/Writer/Word2007/Header.php | 2 +- src/PhpWord/Writer/Word2007/Rels.php | 2 +- .../{IWriter.php => WriterInterface.php} | 2 +- tests/PhpWord/Tests/Element/FooterTest.php | 8 +- tests/PhpWord/Tests/Element/HeaderTest.php | 8 +- tests/PhpWord/Tests/Element/PageBreakTest.php | 1 - tests/PhpWord/Tests/Element/SectionTest.php | 10 +- tests/PhpWord/Tests/MediaTest.php | 2 +- tests/PhpWord/Tests/PhpWordTest.php | 2 +- tests/PhpWord/Tests/Style/SectionTest.php | 36 +-- ...artTest.php => AbstractWriterPartTest.php} | 12 +- ...artTest.php => AbstractWriterPartTest.php} | 14 +- .../Tests/Writer/Word2007/FooterTest.php | 2 +- .../Tests/Writer/Word2007/HeaderTest.php | 2 +- 57 files changed, 284 insertions(+), 310 deletions(-) delete mode 100644 src/PhpWord/Element/Element.php rename src/PhpWord/Reader/{Reader.php => AbstractReader.php} (91%) rename src/PhpWord/Reader/{IReader.php => ReaderInterface.php} (86%) rename src/PhpWord/Writer/{Writer.php => AbstractWriter.php} (98%) rename src/PhpWord/Writer/ODText/{WriterPart.php => AbstractWriterPart.php} (73%) rename src/PhpWord/Writer/Word2007/{WriterPart.php => AbstractWriterPart.php} (80%) rename src/PhpWord/Writer/{IWriter.php => WriterInterface.php} (93%) rename tests/PhpWord/Tests/Writer/ODText/{WriterPartTest.php => AbstractWriterPartTest.php} (69%) rename tests/PhpWord/Tests/Writer/Word2007/{WriterPartTest.php => AbstractWriterPartTest.php} (66%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3ed441..1e159009 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,8 +39,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers - `createHeader` replaced by `addHeader` - `createFooter` replaced by `addFooter` - `createSection` replaced by `addSection` -- `Element\Footnote::getReferenceId` replaced by `Container\Container::getRelationId` -- `Element\Footnote::setReferenceId` replaced by `Container\Container::setRelationId` +- `Element\Footnote::getReferenceId` replaced by `Element\AbstractElement::getRelationId` +- `Element\Footnote::setReferenceId` replaced by `Element\AbstractElement::setRelationId` - `Footnote::addFootnoteLinkElement` replaced by `Media::addElement` - `Footnote::getFootnoteLinkElements` replaced by `Media::getElements` - All current methods on `Media` @@ -48,14 +48,14 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Miscellaneous - Documentation: Simplify page level docblock - @ivanlanin GH-179 -- Writer: Refactor writer classes and make a new Writer abstract class - @ivanlanin GH-160 -- Reader: Rename AbstractReader > Reader - @ivanlanin -- General: Refactor folders: Element, Container, and Exception - @ivanlanin GH-187 +- Writer: Refactor writer classes and make a new AbstractWriter abstract class - @ivanlanin GH-160 +- General: Refactor folders: Element and Exception - @ivanlanin GH-187 - General: Remove legacy HashTable and ZipStreamWrapper and all related properties/methods - @ivanlanin GH-187 -- Container: Create new Container abstract class - @ivanlanin GH-187 -- Element: Create new Element abstract class - @ivanlanin GH-187 +- Element: Create new AbstractElement abstract class - @ivanlanin GH-187 - Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 -- General: Remove underscore prefix from all private properties name +- General: Remove underscore prefix from all private properties name - @ivanlanin GH-187 +- General: Move Section Settings to Style\Section - @ivanlanin GH-187 +- General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 2584a1f7..eabb1963 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -7,7 +7,7 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Container; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\InvalidObjectException; @@ -35,7 +35,7 @@ use PhpOffice\PhpWord\Element\CheckBox; * * @since 0.9.2 */ -abstract class Container extends Element +abstract class AbstractElement { /** * Container type section|header|footer|cell|textrun|footnote @@ -51,6 +51,28 @@ abstract class Container extends Element */ protected $sectionId; + /** + * Document part type: section|header|footer + * + * Used by textrun and cell container to determine where the element is + * located because it will affect the availability of other element, + * e.g. footnote will not be available when $docPart is header or footer. + * + * @var string + */ + private $docPart = 'section'; + + /** + * Document part Id + * + * For header and footer, this will be = ($sectionId - 1) * 3 + $index + * because the max number of header/footer in every page is 3, i.e. + * AUTO, FIRST, and EVEN (AUTO = ODD) + * + * @var integer + */ + private $docPartId = 1; + /** * Elements collection * @@ -340,6 +362,38 @@ abstract class Container extends Element return $this->sectionId; } + /** + * Set doc part + * + * @param string $docPart + * @param integer $docPartId + */ + public function setDocPart($docPart, $docPartId = 1) + { + $this->docPart = $docPart; + $this->docPartId = $docPartId; + } + + /** + * Get doc part + * + * @return string + */ + public function getDocPart() + { + return $this->docPart; + } + + /** + * Get doc part Id + * + * @return integer + */ + public function getDocPartId() + { + return $this->docPartId; + } + /** * Get all elements * @@ -372,6 +426,106 @@ abstract class Container extends Element $this->relationId = $rId; } + /** + * Check if element is located in section doc part (as opposed to header/footer) + * + * @return boolean + */ + public function isInSection() + { + return ($this->docPart == 'section'); + } + + /** + * Set style value + * + * @param mixed $styleObject Style object + * @param mixed $styleValue Style value + * @param boolean $returnObject Always return object + */ + protected function setStyle($styleObject, $styleValue = null, $returnObject = false) + { + if (!is_null($styleValue) && is_array($styleValue)) { + foreach ($styleValue as $key => $value) { + if (substr($key, 0, 1) == '_') { + $key = substr($key, 1); + } + $styleObject->setStyleValue($key, $value); + } + $style = $styleObject; + } else { + $style = $returnObject ? $styleObject : $styleValue; + } + + return $style; + } + + /** + * Check if a method is allowed for the current container + * + * @param string $method + * @return boolean + */ + private function checkValidity($method) + { + // Valid containers for each element + $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote'); + $validContainers = array( + 'text' => $allContainers, + 'link' => $allContainers, + 'textbreak' => $allContainers, + 'image' => $allContainers, + 'object' => $allContainers, + 'textrun' => array('section', 'header', 'footer', 'cell'), + 'listitem' => array('section', 'header', 'footer', 'cell'), + 'checkbox' => array('section', 'header', 'footer', 'cell'), + 'table' => array('section', 'header', 'footer'), + 'footnote' => array('section', 'textrun', 'cell'), + 'preservetext' => array('header', 'footer', 'cell'), + 'relationid' => array('header', 'footer', 'footnote'), + 'title' => array('section'), + ); + // Special condition, e.g. preservetext can only exists in cell when + // the cell is located in header or footer + $validContainerInContainers = array( + 'preservetext' => array(array('cell'), array('header', 'footer')), + 'footnote' => array(array('cell', 'textrun'), array('section')), + ); + + // Check if a method is valid for current container + if (array_key_exists($method, $validContainers)) { + if (!in_array($this->container, $validContainers[$method])) { + throw new \BadMethodCallException(); + } + } + // Check if a method is valid for current container, located in other container + if (array_key_exists($method, $validContainerInContainers)) { + $rules = $validContainerInContainers[$method]; + $containers = $rules[0]; + $allowedDocParts = $rules[1]; + foreach ($containers as $container) { + if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { + throw new \BadMethodCallException(); + } + } + } + + return true; + } + + /** + * Return element location in document: section, headerx, or footerx + */ + private function checkElementDocPart() + { + $isCellTextrun = in_array($this->container, array('cell', 'textrun')); + $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; + $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId; + $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); + + return $inHeaderFooter ? $docPart . $docPartId : $docPart; + } + /** * Add memory image element * @@ -408,71 +562,4 @@ abstract class Container extends Element { return $this->addFootnote($paragraphStyle); } - - /** - * Check if a method is allowed for the current container - * - * @param string $method - * @return boolean - */ - private function checkValidity($method) - { - // Empty array means the element can be accepted by all containers - $validContainers = array( - 'text' => array(), - 'link' => array(), - 'textbreak' => array(), - 'image' => array(), - 'object' => array(), - 'textrun' => array('section', 'header', 'footer', 'cell'), - 'listitem' => array('section', 'header', 'footer', 'cell'), - 'checkbox' => array('section', 'header', 'footer', 'cell'), - 'table' => array('section', 'header', 'footer'), - 'footnote' => array('section', 'textrun', 'cell'), - 'preservetext' => array('header', 'footer', 'cell'), - 'relationid' => array('header', 'footer', 'footnote'), - 'title' => array('section'), - ); - // Special condition, e.g. preservetext can only exists in cell when - // the cell is located in header or footer - $validContainerInContainers = array( - 'preservetext' => array(array('cell'), array('header', 'footer')), - 'footnote' => array(array('cell', 'textrun'), array('section')), - ); - - // Check if a method is valid for current container - if (array_key_exists($method, $validContainers)) { - if (!empty($validContainers[$method])) { - if (!in_array($this->container, $validContainers[$method])) { - throw new \BadMethodCallException(); - } - } - } - // Check if a method is valid for current container, located in other container - if (array_key_exists($method, $validContainerInContainers)) { - $rules = $validContainerInContainers[$method]; - $containers = $rules[0]; - $allowedDocParts = $rules[1]; - foreach ($containers as $container) { - if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { - throw new \BadMethodCallException(); - } - } - } - - return true; - } - - /** - * Return element location in document: section, headerx, or footerx - */ - private function checkElementDocPart() - { - $isCellTextrun = in_array($this->container, array('cell', 'textrun')); - $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; - $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId; - $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); - - return $inHeaderFooter ? $docPart . $docPartId : $docPart; - } } diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php index 5e035fb7..2f92bce1 100755 --- a/src/PhpWord/Element/Cell.php +++ b/src/PhpWord/Element/Cell.php @@ -9,13 +9,12 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Cell as CellStyle; /** * Table cell element */ -class Cell extends Container +class Cell extends AbstractElement { /** * Cell width diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php index 187bd132..31f067d7 100644 --- a/src/PhpWord/Element/CheckBox.php +++ b/src/PhpWord/Element/CheckBox.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Check box element */ -class CheckBox extends Element +class CheckBox extends AbstractElement { /** * Name content diff --git a/src/PhpWord/Element/Element.php b/src/PhpWord/Element/Element.php deleted file mode 100644 index 6cebd0d5..00000000 --- a/src/PhpWord/Element/Element.php +++ /dev/null @@ -1,106 +0,0 @@ - $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - $styleObject->setStyleValue($key, $value); - } - $style = $styleObject; - } else { - $style = $returnObject ? $styleObject : $styleValue; - } - - return $style; - } - - /** - * Set doc part - * - * @param string $docPart - * @param integer $docPartId - */ - public function setDocPart($docPart, $docPartId = 1) - { - $this->docPart = $docPart; - $this->docPartId = $docPartId; - } - - /** - * Get doc part - * - * @return string - */ - public function getDocPart() - { - return $this->docPart; - } - - /** - * Get doc part Id - * - * @return integer - */ - public function getDocPartId() - { - return $this->docPartId; - } - - /** - * Check if element is located in section doc part (as opposed to header/footer) - * - * @return boolean - */ - public function isInSection() - { - return ($this->docPart == 'section'); - } -} diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 47287c8b..6d441126 100755 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Container; +namespace PhpOffice\PhpWord\Element; /** * Footer element */ -class Footer extends Container +class Footer extends AbstractElement { const AUTO = 'default'; // default and odd pages const FIRST = 'first'; diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index ff0c9960..e79e9c79 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -9,13 +9,12 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Paragraph; /** * Footnote element */ -class Footnote extends Container +class Footnote extends AbstractElement { /** * Paragraph style diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index 2920e3cf..c14ed0e7 100755 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Container; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Element\Image; /** * Header element */ -class Header extends Container +class Header extends AbstractElement { /** * Header types constants diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index fec8791c..bf29220b 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Image element */ -class Image extends Element +class Image extends AbstractElement { /** * Image source @@ -138,9 +138,6 @@ class Image extends Element $this->source = $source; $this->isWatermark = $isWatermark; $this->style = $this->setStyle(new ImageStyle(), $style, true); - if (isset($style['wrappingStyle'])) { - $this->style->setWrappingStyle($style['wrappingStyle']); - } if ($this->style->getWidth() == null && $this->style->getHeight() == null) { $this->style->setWidth($imgData[0]); $this->style->setHeight($imgData[1]); diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index ee1af203..96c66339 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Link element */ -class Link extends Element +class Link extends AbstractElement { /** * Link source diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 6cf5d1d6..64ac149d 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** * List item element */ -class ListItem extends Element +class ListItem extends AbstractElement { /** * ListItem Style diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 5716b7e6..f6b4161b 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; /** * Object element */ -class Object extends Element +class Object extends AbstractElement { /** * Ole-Object Src diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php index c297681d..d2f85f20 100644 --- a/src/PhpWord/Element/PageBreak.php +++ b/src/PhpWord/Element/PageBreak.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Element; /** * Page break element */ -class PageBreak extends Element +class PageBreak extends AbstractElement { /** * Create new page break diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 0fe77d9a..76e860fe 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Preserve text/field element */ -class PreserveText extends Element +class PreserveText extends AbstractElement { /** * Text content diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php index 53990850..c20b018b 100644 --- a/src/PhpWord/Element/Row.php +++ b/src/PhpWord/Element/Row.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Style\Row as RowStyle; /** * Table row element */ -class Row extends Element +class Row extends AbstractElement { /** * Row height diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index dae4f26c..2be0794a 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -7,24 +7,24 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Container; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Container\Footer; -use PhpOffice\PhpWord\Container\Header; -use PhpOffice\PhpWord\Container\Settings; +use PhpOffice\PhpWord\Element\Footer; +use PhpOffice\PhpWord\Element\Header; use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Style\Section as SectionSettings; /** * Section */ -class Section extends Container +class Section extends AbstractElement { /** * Section settings * - * @var Settings + * @var SectionSettings */ private $settings; @@ -53,7 +53,7 @@ class Section extends Container $this->container = 'section'; $this->sectionId = $sectionCount; $this->setDocPart($this->container, $this->sectionId); - $this->settings = new Settings(); + $this->settings = new SectionSettings(); $this->setSettings($settings); } @@ -77,7 +77,7 @@ class Section extends Container /** * Get Section Settings * - * @return Settings + * @return SectionSettings */ public function getSettings() { @@ -181,7 +181,7 @@ class Section extends Container private function addHeaderFooter($type = Header::AUTO, $header = true) { $collectionArray = $header ? 'headers' : 'footers'; - $containerClass = 'PhpOffice\\PhpWord\\Container\\'; + $containerClass = 'PhpOffice\\PhpWord\\Element\\'; $containerClass .= ($header ? 'Header' : 'Footer'); $collection = &$this->$collectionArray; diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 5808a065..0c8d494d 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Table as TableStyle; /** * Table element */ -class Table extends Element +class Table extends AbstractElement { /** * Table style diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 620095b8..bb1d5aac 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text element */ -class Text extends Element +class Text extends AbstractElement { /** * Text content diff --git a/src/PhpWord/Element/TextBreak.php b/src/PhpWord/Element/TextBreak.php index adf144ba..aa3d5cca 100755 --- a/src/PhpWord/Element/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text break element */ -class TextBreak extends Element +class TextBreak extends AbstractElement { /** * Paragraph style diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php index 6be08fc4..f7286d8f 100755 --- a/src/PhpWord/Element/TextRun.php +++ b/src/PhpWord/Element/TextRun.php @@ -9,13 +9,12 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Container\Container; use PhpOffice\PhpWord\Style\Paragraph; /** * Textrun/paragraph element */ -class TextRun extends Container +class TextRun extends AbstractElement { /** * Paragraph style diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index c8c29a35..5ed1bfbc 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Element; /** * Title element */ -class Title extends Element +class Title extends AbstractElement { /** * Title Text content diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index eeafb057..7b32ef44 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -21,12 +21,12 @@ abstract class IOFactory * * @param \PhpOffice\PhpWord\PhpWord $phpWord * @param string $name - * @return \PhpOffice\PhpWord\Writer\IWriter + * @return \PhpOffice\PhpWord\Writer\WriterInterface * @throws Exception */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'IWriter' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { + if ($name !== 'WriterInterface' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { throw new Exception("\"{$name}\" is not a valid writer."); } @@ -38,12 +38,12 @@ abstract class IOFactory * Create new reader * * @param string $name - * @return \PhpOffice\PhpWord\Reader\IReader + * @return \PhpOffice\PhpWord\Reader\ReaderInterface * @throws Exception */ public static function createReader($name = 'Word2007') { - if ($name !== 'IReader' && $name !== 'Word2007') { + if ($name !== 'ReaderInterface' && $name !== 'Word2007') { throw new Exception("\"{$name}\" is not a valid reader."); } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 447706af..63d26a09 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -11,7 +11,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\DocumentProperties; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Template; @@ -217,7 +217,7 @@ class PhpWord /** * Get all sections * - * @return \PhpOffice\PhpWord\Container\Section[] + * @return \PhpOffice\PhpWord\Element\Section[] */ public function getSections() { diff --git a/src/PhpWord/Reader/Reader.php b/src/PhpWord/Reader/AbstractReader.php similarity index 91% rename from src/PhpWord/Reader/Reader.php rename to src/PhpWord/Reader/AbstractReader.php index e93b4636..10c864f3 100644 --- a/src/PhpWord/Reader/Reader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Exception\Exception; * * @codeCoverageIgnore Abstract class */ -abstract class Reader implements IReader +abstract class AbstractReader implements ReaderInterface { /** * Read data only? @@ -47,7 +47,7 @@ abstract class Reader implements IReader * Set read data only * * @param bool $pValue - * @return \PhpOffice\PhpWord\Reader\IReader + * @return \PhpOffice\PhpWord\Reader\ReaderInterface */ public function setReadDataOnly($pValue = true) { @@ -77,7 +77,7 @@ abstract class Reader implements IReader } /** - * Can the current IReader read the file? + * Can the current ReaderInterface read the file? * * @param string $pFilename * @return bool diff --git a/src/PhpWord/Reader/IReader.php b/src/PhpWord/Reader/ReaderInterface.php similarity index 86% rename from src/PhpWord/Reader/IReader.php rename to src/PhpWord/Reader/ReaderInterface.php index a4bea94e..2829d4ab 100644 --- a/src/PhpWord/Reader/IReader.php +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -12,10 +12,10 @@ namespace PhpOffice\PhpWord\Reader; /** * Reader interface */ -interface IReader +interface ReaderInterface { /** - * Can the current IReader read the file? + * Can the current ReaderInterface read the file? * * @param string $pFilename * @return boolean diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 2cdb7f9a..3d26bb63 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -17,10 +17,10 @@ use PhpOffice\PhpWord\Exception\Exception; /** * Reader for Word2007 */ -class Word2007 extends Reader implements IReader +class Word2007 extends AbstractReader implements ReaderInterface { /** - * Can the current IReader read the file? + * Can the current ReaderInterface read the file? * * @param string $pFilename * @return bool diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 762d45c3..52352434 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Container; +namespace PhpOffice\PhpWord\Style; /** * Section settings */ -class Settings +class Section { /** * Default Page Size Width diff --git a/src/PhpWord/Writer/Writer.php b/src/PhpWord/Writer/AbstractWriter.php similarity index 98% rename from src/PhpWord/Writer/Writer.php rename to src/PhpWord/Writer/AbstractWriter.php index e53d215a..b4f4b765 100644 --- a/src/PhpWord/Writer/Writer.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -17,7 +17,7 @@ use PhpOffice\PhpWord\PhpWord; * * @since 0.9.2 */ -abstract class Writer implements IWriter +abstract class AbstractWriter implements WriterInterface { /** * PHPWord object diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 10e90dd3..7e1da98c 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -21,7 +21,7 @@ use PhpOffice\PhpWord\Writer\ODText\Styles; /** * ODText writer */ -class ODText extends Writer implements IWriter +class ODText extends AbstractWriter implements WriterInterface { /** * Create new ODText writer diff --git a/src/PhpWord/Writer/ODText/WriterPart.php b/src/PhpWord/Writer/ODText/AbstractWriterPart.php similarity index 73% rename from src/PhpWord/Writer/ODText/WriterPart.php rename to src/PhpWord/Writer/ODText/AbstractWriterPart.php index a6fa93cb..1a5831e0 100644 --- a/src/PhpWord/Writer/ODText/WriterPart.php +++ b/src/PhpWord/Writer/ODText/AbstractWriterPart.php @@ -12,6 +12,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; /** * ODText writer part abstract */ -abstract class WriterPart extends \PhpOffice\PhpWord\Writer\Word2007\WriterPart +abstract class AbstractWriterPart extends \PhpOffice\PhpWord\Writer\Word2007\AbstractWriterPart { } diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 7fc0d2df..b902ffb3 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -29,7 +29,7 @@ use PhpOffice\PhpWord\TOC; /** * ODText content part writer */ -class Content extends WriterPart +class Content extends AbstractWriterPart { /** * Write content file to XML format diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index ecda1918..e94a1fd1 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\PhpWord; /** * ODText manifest part writer */ -class Manifest extends WriterPart +class Manifest extends AbstractWriterPart { /** * Write Manifest file to XML format diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index fc5314e9..0df77827 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\PhpWord; /** * ODText meta part writer */ -class Meta extends WriterPart +class Meta extends AbstractWriterPart { /** * Write Meta file to XML format diff --git a/src/PhpWord/Writer/ODText/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php index 1e713f2c..b8bc6539 100644 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Mimetype.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\PhpWord; /** * ODText mimetype part writer */ -class Mimetype extends WriterPart +class Mimetype extends AbstractWriterPart { /** * Write Mimetype to Text format diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 8839f568..306ee5fc 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -18,7 +18,7 @@ use PhpOffice\PhpWord\Style\Table; /** * ODText styloes part writer */ -class Styles extends WriterPart +class Styles extends AbstractWriterPart { /** * Write Styles file to XML format diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 8698365f..2505a76d 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -29,7 +29,7 @@ use PhpOffice\PhpWord\TOC; /** * RTF writer */ -class RTF extends Writer implements IWriter +class RTF extends AbstractWriter implements WriterInterface { /** * Color register diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 8fe90339..b426d570 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -26,7 +26,7 @@ use PhpOffice\PhpWord\Writer\Word2007\Styles; /** * Word2007 writer */ -class Word2007 extends Writer implements IWriter +class Word2007 extends AbstractWriter implements WriterInterface { /** * Content types values @@ -229,7 +229,7 @@ class Word2007 extends Writer implements IWriter /** * Add header/footer content * - * @param \PhpOffice\PhpWord\Container\Section $section + * @param \PhpOffice\PhpWord\Element\Section $section * @param mixed $objZip * @param string $elmType * @param integer $rID diff --git a/src/PhpWord/Writer/Word2007/WriterPart.php b/src/PhpWord/Writer/Word2007/AbstractWriterPart.php similarity index 80% rename from src/PhpWord/Writer/Word2007/WriterPart.php rename to src/PhpWord/Writer/Word2007/AbstractWriterPart.php index a61662e9..b58797db 100755 --- a/src/PhpWord/Writer/Word2007/WriterPart.php +++ b/src/PhpWord/Writer/Word2007/AbstractWriterPart.php @@ -10,27 +10,27 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Writer\IWriter; +use PhpOffice\PhpWord\Writer\WriterInterface; use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 writer part abstract class */ -abstract class WriterPart +abstract class AbstractWriterPart { /** * Parent writer * - * @var IWriter + * @var WriterInterface */ protected $parentWriter; /** * Set parent writer * - * @param IWriter $pWriter + * @param WriterInterface $pWriter */ - public function setParentWriter(IWriter $pWriter = null) + public function setParentWriter(WriterInterface $pWriter = null) { $this->parentWriter = $pWriter; } @@ -38,7 +38,7 @@ abstract class WriterPart /** * Get parent writer * - * @return IWriter + * @return WriterInterface * @throws Exception */ public function getParentWriter() @@ -46,7 +46,7 @@ abstract class WriterPart if (!is_null($this->parentWriter)) { return $this->parentWriter; } else { - throw new Exception("No parent IWriter assigned."); + throw new Exception("No parent WriterInterface assigned."); } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 762bc7ea..a5f9a5e0 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -11,7 +11,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Container\Container; +use PhpOffice\PhpWord\Element\AbstractElement; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\Link; @@ -37,7 +37,7 @@ use PhpOffice\PhpWord\Style\Image as ImageStyle; * * Write common parts of document.xml, headerx.xml, and footerx.xml */ -class Base extends WriterPart +class Base extends AbstractWriterPart { /** * Write text element @@ -1121,9 +1121,9 @@ class Base extends WriterPart * Write container elements * * @param XMLWriter $xmlWriter - * @param Container $container + * @param AbstractElement $container */ - protected function writeContainerElements(XMLWriter $xmlWriter, Container $container) + protected function writeContainerElements(XMLWriter $xmlWriter, AbstractElement $container) { // Check allowed elements $elmCommon = array('Text', 'Link', 'TextBreak', 'Image', 'Object'); diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php index 8eb10bc1..a27ef43c 100755 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ b/src/PhpWord/Writer/Word2007/ContentTypes.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 contenttypes part writer */ -class ContentTypes extends WriterPart +class ContentTypes extends AbstractWriterPart { /** * Write [Content_Types].xml diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php index cfa238e5..5818d511 100644 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ b/src/PhpWord/Writer/Word2007/DocProps.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\PhpWord; /** * Word2007 contenttypes part writer */ -class DocProps extends WriterPart +class DocProps extends AbstractWriterPart { /** * Write docProps/app.xml diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 2b5e6e95..9cc53375 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -11,7 +11,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\PageBreak; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php index 4b075b97..dc726114 100644 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ b/src/PhpWord/Writer/Word2007/Footer.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Container\Footer as FooterElement; +use PhpOffice\PhpWord\Element\Footer as FooterElement; /** * Word2007 footer part writer diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php index 3f649261..95e57340 100644 --- a/src/PhpWord/Writer/Word2007/Header.php +++ b/src/PhpWord/Writer/Word2007/Header.php @@ -9,7 +9,7 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\Container\Header as HeaderElement; +use PhpOffice\PhpWord\Element\Header as HeaderElement; /** * Word2007 header part writer diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index d7552410..c708eeaf 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -17,7 +17,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; * * @since 0.9.2 */ -class Rels extends WriterPart +class Rels extends AbstractWriterPart { /** * Base relationship URL diff --git a/src/PhpWord/Writer/IWriter.php b/src/PhpWord/Writer/WriterInterface.php similarity index 93% rename from src/PhpWord/Writer/IWriter.php rename to src/PhpWord/Writer/WriterInterface.php index ea69b830..2c225b2c 100755 --- a/src/PhpWord/Writer/IWriter.php +++ b/src/PhpWord/Writer/WriterInterface.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Writer; /** * Writer interface */ -interface IWriter +interface WriterInterface { /** * Save PhpWord to file diff --git a/tests/PhpWord/Tests/Element/FooterTest.php b/tests/PhpWord/Tests/Element/FooterTest.php index db982dc5..d4201149 100644 --- a/tests/PhpWord/Tests/Element/FooterTest.php +++ b/tests/PhpWord/Tests/Element/FooterTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Container; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Container\Footer; +use PhpOffice\PhpWord\Element\Footer; /** - * Test class for PhpOffice\PhpWord\Container\Footer + * Test class for PhpOffice\PhpWord\Element\Footer * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oFooter = new Footer($iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Footer', $oFooter); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footer', $oFooter); $this->assertEquals($oFooter->getSectionId(), $iVal); } diff --git a/tests/PhpWord/Tests/Element/HeaderTest.php b/tests/PhpWord/Tests/Element/HeaderTest.php index ef1703f3..849dd220 100644 --- a/tests/PhpWord/Tests/Element/HeaderTest.php +++ b/tests/PhpWord/Tests/Element/HeaderTest.php @@ -7,12 +7,12 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Container; +namespace PhpOffice\PhpWord\Tests\Element; -use PhpOffice\PhpWord\Container\Header; +use PhpOffice\PhpWord\Element\Header; /** - * Test class for PhpOffice\PhpWord\Container\Header + * Test class for PhpOffice\PhpWord\Element\Header * * @runTestsInSeparateProcesses */ @@ -26,7 +26,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oHeader = new Header($iVal); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Header', $oHeader); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Header', $oHeader); $this->assertEquals($oHeader->getSectionId(), $iVal); $this->assertEquals($oHeader->getType(), Header::AUTO); } diff --git a/tests/PhpWord/Tests/Element/PageBreakTest.php b/tests/PhpWord/Tests/Element/PageBreakTest.php index 3dbaad87..0c6379f5 100644 --- a/tests/PhpWord/Tests/Element/PageBreakTest.php +++ b/tests/PhpWord/Tests/Element/PageBreakTest.php @@ -24,7 +24,6 @@ class PageBreakTest extends \PHPUnit_Framework_TestCase */ public function testConstruct() { - // Section Settings $oPageBreak = new PageBreak(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PageBreak', $oPageBreak); diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php index e077ff82..d41a1e1f 100644 --- a/tests/PhpWord/Tests/Element/SectionTest.php +++ b/tests/PhpWord/Tests/Element/SectionTest.php @@ -7,15 +7,15 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Container; +namespace PhpOffice\PhpWord\Tests\Element; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Container\Section; -use PhpOffice\PhpWord\Container\Header; +use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Element\Header; use PhpOffice\PhpWord\Style; /** - * Test class for PhpOffice\PhpWord\Container\Section + * Test class for PhpOffice\PhpWord\Element\Section * * @runTestsInSeparateProcesses */ @@ -139,7 +139,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase foreach ($elements as $element) { $method = "create{$element}"; - $this->assertInstanceOf("PhpOffice\\PhpWord\\Container\\{$element}", $object->$method()); + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$element}", $object->$method()); } $this->assertFalse($object->hasDifferentFirstPage()); } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 14a38c2d..93dfaf87 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -10,7 +10,7 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\Image; /** diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index 829ddfff..efef7053 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -11,7 +11,7 @@ namespace PhpOffice\PhpWord\Tests; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Container\Section; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Style; /** diff --git a/tests/PhpWord/Tests/Style/SectionTest.php b/tests/PhpWord/Tests/Style/SectionTest.php index 3d5ae43a..542a0f25 100644 --- a/tests/PhpWord/Tests/Style/SectionTest.php +++ b/tests/PhpWord/Tests/Style/SectionTest.php @@ -7,14 +7,14 @@ * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Tests\Container; +namespace PhpOffice\PhpWord\Tests\Style; -use PhpOffice\PhpWord\Container\Settings; +use PhpOffice\PhpWord\Style\Section; /** - * Test class for PhpOffice\PhpWord\Container\Settings + * Test class for PhpOffice\PhpWord\Style\Section * - * @coversDefaultClass \PhpOffice\PhpWord\Container\Settings + * @coversDefaultClass \PhpOffice\PhpWord\Element\Section * @runTestsInSeparateProcesses */ class SettingsTest extends \PHPUnit_Framework_TestCase @@ -25,7 +25,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testSettingValue() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setSettingValue('_orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); @@ -63,7 +63,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testMargin() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $iVal = rand(1, 1000); $oSettings->setMarginTop($iVal); @@ -88,7 +88,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testOrientationLandscape() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setLandscape(); $this->assertEquals('landscape', $oSettings->getOrientation()); @@ -102,7 +102,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testOrientationPortrait() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setPortrait(); $this->assertNull($oSettings->getOrientation()); @@ -116,7 +116,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testBorderSize() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $iVal = rand(1, 1000); $oSettings->setBorderSize($iVal); @@ -149,7 +149,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testBorderColor() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setBorderColor('FF00AA'); $this->assertEquals(array('FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'), $oSettings->getBorderColor()); @@ -177,7 +177,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testNumberingStart() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertNull($oSettings->getPageNumberingStart()); @@ -194,7 +194,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase */ public function testHeader() { - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertEquals(720, $oSettings->getHeaderHeight()); @@ -212,7 +212,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testFooter() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertEquals(720, $oSettings->getFooterHeight()); @@ -230,7 +230,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testColumnsNum() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); // Default $this->assertEquals(1, $oSettings->getColsNum()); @@ -249,16 +249,16 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testColumnsSpace() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); // Default $this->assertEquals(720, $oSettings->getColsSpace()); $iVal = rand(1, 1000); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Settings', $oSettings->setColsSpace($iVal)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace($iVal)); $this->assertEquals($iVal, $oSettings->getColsSpace()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Container\\Settings', $oSettings->setColsSpace()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace()); $this->assertEquals(720, $oSettings->getColsSpace()); } @@ -268,7 +268,7 @@ class SettingsTest extends \PHPUnit_Framework_TestCase public function testBreakType() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertNull($oSettings->getBreakType()); diff --git a/tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php b/tests/PhpWord/Tests/Writer/ODText/AbstractWriterPartTest.php similarity index 69% rename from tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php rename to tests/PhpWord/Tests/Writer/ODText/AbstractWriterPartTest.php index 19f17ee5..a8863087 100644 --- a/tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/AbstractWriterPartTest.php @@ -12,12 +12,12 @@ use PhpOffice\PhpWord\Writer\ODText; use PhpWord\Tests\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\ODText\WriterPart + * Test class for PhpOffice\PhpWord\Writer\ODText\AbstractWriterPart * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\WriterPart + * @coversDefaultClass \PhpOffice\PhpWord\Writer\ODText\AbstractWriterPart * @runTestsInSeparateProcesses */ -class WriterPartTest extends \PHPUnit_Framework_TestCase +class AbstractWriterPartTest extends \PHPUnit_Framework_TestCase { /** * covers ::setParentWriter @@ -26,7 +26,7 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase public function testSetGetParentWriter() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\ODText\\AbstractWriterPart' ); $object->setParentWriter(new ODText()); $this->assertEquals( @@ -38,12 +38,12 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase /** * covers ::getParentWriter * @expectedException Exception - * @expectedExceptionMessage No parent IWriter assigned. + * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\ODText\\AbstractWriterPart' ); $object->getParentWriter(); } diff --git a/tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php b/tests/PhpWord/Tests/Writer/Word2007/AbstractWriterPartTest.php similarity index 66% rename from tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php rename to tests/PhpWord/Tests/Writer/Word2007/AbstractWriterPartTest.php index 5cbe9eb9..33051d6f 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/AbstractWriterPartTest.php @@ -8,17 +8,17 @@ */ namespace PhpOffice\PhpWord\Tests\Writer\Word2007; -use PhpOffice\PhpWord\Writer\Word2007\WriterPart; +use PhpOffice\PhpWord\Writer\Word2007\AbstractWriterPart; use PhpOffice\PhpWord\Writer\Word2007; use PhpWord\Tests\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\Word2007\WriterPart + * Test class for PhpOffice\PhpWord\Writer\Word2007\AbstractWriterPart * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\WriterPart + * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\AbstractWriterPart * @runTestsInSeparateProcesses */ -class WriterPartTest extends \PHPUnit_Framework_TestCase +class AbstractWriterPartTest extends \PHPUnit_Framework_TestCase { /** * covers ::setParentWriter @@ -27,7 +27,7 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase public function testSetGetParentWriter() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\Word2007\\AbstractWriterPart' ); $object->setParentWriter(new Word2007()); $this->assertEquals( @@ -39,12 +39,12 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase /** * covers ::getParentWriter * @expectedException Exception - * @expectedExceptionMessage No parent IWriter assigned. + * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\Word2007\\AbstractWriterPart' ); $object->getParentWriter(); } diff --git a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php index 04e86832..b1bff02b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php @@ -28,7 +28,7 @@ class FooterTest extends \PHPUnit_Framework_TestCase public function testWriteFooter() { $imageSrc = __DIR__ . "/../../_files/images/PhpWord.png"; - $container = new \PhpOffice\PhpWord\Container\Footer(1); + $container = new \PhpOffice\PhpWord\Element\Footer(1); $container->addText(''); $container->addPreserveText(''); $container->addTextBreak(); diff --git a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php index c468d7a7..b836b619 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php @@ -26,7 +26,7 @@ class HeaderTest extends \PHPUnit_Framework_TestCase { $imageSrc = __DIR__ . "/../../_files/images/PhpWord.png"; - $container = new \PhpOffice\PhpWord\Container\Header(1); + $container = new \PhpOffice\PhpWord\Element\Header(1); $container->addText('Test'); $container->addPreserveText(''); $container->addTextBreak(); From 3ef0f41c252aa3a3a4591bfa5660aaae8bedc389 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 8 Apr 2014 03:03:14 +0700 Subject: [PATCH 067/146] New `Style\AbstractStyle` and 'ODText\Base` --- CHANGELOG.md | 14 ++-- src/PhpWord/Style/AbstractStyle.php | 43 ++++++++++++ src/PhpWord/Style/Cell.php | 2 +- src/PhpWord/Style/Font.php | 19 +----- src/PhpWord/Style/Image.php | 30 +++------ src/PhpWord/Style/ListItem.php | 16 +---- src/PhpWord/Style/Paragraph.php | 2 +- src/PhpWord/Style/Row.php | 16 +---- src/PhpWord/Style/Section.php | 2 +- src/PhpWord/Style/TOC.php | 2 +- src/PhpWord/Style/Tab.php | 2 +- src/PhpWord/Style/Table.php | 2 +- src/PhpWord/Style/Tabs.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 52 +++++++++++--- src/PhpWord/Writer/ODText.php | 31 ++------- src/PhpWord/Writer/ODText/Base.php | 93 ++++++++++++++++++++++++++ src/PhpWord/Writer/ODText/Content.php | 62 ++--------------- src/PhpWord/Writer/ODText/Manifest.php | 2 +- src/PhpWord/Writer/ODText/Meta.php | 2 +- src/PhpWord/Writer/ODText/Styles.php | 61 +---------------- src/PhpWord/Writer/Word2007.php | 32 ++------- 21 files changed, 225 insertions(+), 262 deletions(-) create mode 100644 src/PhpWord/Style/AbstractStyle.php create mode 100644 src/PhpWord/Writer/ODText/Base.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e159009..bc43822b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.9.2 - Not yet released +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. + ### Features - Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 @@ -48,14 +50,16 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ### Miscellaneous - Documentation: Simplify page level docblock - @ivanlanin GH-179 -- Writer: Refactor writer classes and make a new AbstractWriter abstract class - @ivanlanin GH-160 -- General: Refactor folders: Element and Exception - @ivanlanin GH-187 -- General: Remove legacy HashTable and ZipStreamWrapper and all related properties/methods - @ivanlanin GH-187 -- Element: Create new AbstractElement abstract class - @ivanlanin GH-187 +- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin GH-160 +- General: Refactor folders: `Element` and `Exception` - @ivanlanin GH-187 +- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin GH-187 +- Element: New `AbstractElement` abstract class - @ivanlanin GH-187 - Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 - General: Remove underscore prefix from all private properties name - @ivanlanin GH-187 -- General: Move Section Settings to Style\Section - @ivanlanin GH-187 +- General: Move Section `Settings` to `Style\Section` - @ivanlanin GH-187 - General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 +- Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 +- Writer: New 'ODText\Base` class - @ivanlanin GH-187 ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php new file mode 100644 index 00000000..c17ea6e2 --- /dev/null +++ b/src/PhpWord/Style/AbstractStyle.php @@ -0,0 +1,43 @@ +$method($value); + } + } +} diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 1fbed6e7..2e1f9d79 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Table cell style */ -class Cell +class Cell extends AbstractStyle { const TEXT_DIR_BTLR = 'btLr'; const TEXT_DIR_TBRL = 'tbRl'; diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 999fc3fa..2fef3a66 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Exception\InvalidStyleException; /** * Font style */ -class Font +class Font extends AbstractStyle { const UNDERLINE_NONE = 'none'; const UNDERLINE_DASH = 'dash'; @@ -202,23 +202,6 @@ class Font return $this; } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - $method = 'set' . $key; - if (method_exists($this, $method)) { - $this->$method($value); - } - } - /** * Get font name * diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index e973f1ac..49060607 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Image and memory image style */ -class Image +class Image extends AbstractStyle { const WRAPPING_STYLE_INLINE = 'inline'; const WRAPPING_STYLE_SQUARE = 'square'; @@ -41,13 +41,6 @@ class Image */ private $align; - /** - * Wrapping style - * - * @var string - */ - private $wrappingStyle; - /** * Margin Top * @@ -62,6 +55,13 @@ class Image */ private $marginLeft; + /** + * Wrapping style + * + * @var string + */ + private $wrappingStyle; + /** * Create new image style */ @@ -75,20 +75,6 @@ class Image $this->setWrappingStyle(self::WRAPPING_STYLE_INLINE); } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - $this->$key = $value; - } - /** * Get width */ diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 6681be16..ecc4274c 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * List item style */ -class ListItem +class ListItem extends AbstractStyle { const TYPE_NUMBER = 7; const TYPE_NUMBER_NESTED = 8; @@ -34,20 +34,6 @@ class ListItem $this->listType = self::TYPE_BULLET_FILLED; } - /** - * Set style value - * - * @param string $key - * @param string $value - */ - public function setStyleValue($key, $value) - { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - $this->$key = $value; - } - /** * Set List Type * diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index c55d9db1..8feb7924 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Exception\InvalidStyleException; /** * Paragraph style */ -class Paragraph +class Paragraph extends AbstractStyle { const LINE_HEIGHT = 240; diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 113baaf2..d4dc642f 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Table row style */ -class Row +class Row extends AbstractStyle { /** * Repeat table row on every new page @@ -42,20 +42,6 @@ class Row { } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - $this->$key = $value; - } - /** * Set tblHeader * diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 52352434..005ca1e5 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Section settings */ -class Section +class Section extends AbstractStyle { /** * Default Page Size Width diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index f49d9847..f7a752a9 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * TOC style */ -class TOC +class TOC extends AbstractStyle { const TABLEADER_DOT = 'dot'; const TABLEADER_UNDERSCORE = 'underscore'; diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 59757ea8..c28d8923 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Tab style */ -class Tab +class Tab extends AbstractStyle { /** * Tab Stop Type diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index 178c2854..f7c98c36 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Table style */ -class Table +class Table extends AbstractStyle { /** * Style for first row diff --git a/src/PhpWord/Style/Tabs.php b/src/PhpWord/Style/Tabs.php index 497e09f1..66137c0e 100755 --- a/src/PhpWord/Style/Tabs.php +++ b/src/PhpWord/Style/Tabs.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Tabs style */ -class Tabs +class Tabs extends AbstractStyle { /** * Tabs diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index b4f4b765..faa13ea6 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -11,6 +11,7 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Settings; /** * Abstract writer class @@ -148,21 +149,21 @@ abstract class AbstractWriter implements WriterInterface /** * Get temporary file name * - * If $pFilename is php://output or php://stdout, make it a temporary file + * If $filename is php://output or php://stdout, make it a temporary file * - * @param string $pFilename + * @param string $filename * @return string */ - protected function getTempFile($pFilename) + protected function getTempFile($filename) { - $this->originalFilename = $pFilename; - if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { - $pFilename = @tempnam(sys_get_temp_dir(), 'phpword_'); - if ($pFilename == '') { - $pFilename = $this->originalFilename; + $this->originalFilename = $filename; + if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { + $filename = @tempnam(sys_get_temp_dir(), 'phpword_'); + if ($filename == '') { + $filename = $this->originalFilename; } } - $this->tempFilename = $pFilename; + $this->tempFilename = $filename; return $this->tempFilename; } @@ -181,4 +182,37 @@ abstract class AbstractWriter implements WriterInterface @unlink($this->tempFilename); } } + + /** + * Get ZipArchive object + * + * @param string $filename + * @return mixed ZipArchive object + */ + protected function getZipArchive($filename) + { + // Create new ZIP file and open it for writing + $zipClass = Settings::getZipClass(); + $objZip = new $zipClass(); + + // Retrieve OVERWRITE and CREATE constants from the instantiated zip class + // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP + $ro = new \ReflectionObject($objZip); + $zipOverWrite = $ro->getConstant('OVERWRITE'); + $zipCreate = $ro->getConstant('CREATE'); + + // Remove any existing file + if (file_exists($filename)) { + unlink($filename); + } + + // Try opening the ZIP file + if ($objZip->open($filename, $zipOverWrite) !== true) { + if ($objZip->open($filename, $zipCreate) !== true) { + throw new Exception("Could not open " . $filename . " for writing."); + } + } + + return $objZip; + } } diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 7e1da98c..e3b82f4d 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -47,35 +47,14 @@ class ODText extends AbstractWriter implements WriterInterface /** * Save PhpWord to file * - * @param string $pFilename + * @param string $filename * @throws Exception */ - public function save($pFilename = null) + public function save($filename = null) { if (!is_null($this->phpWord)) { - $pFilename = $this->getTempFile($pFilename); - - // Create new ZIP file and open it for writing - $zipClass = Settings::getZipClass(); - $objZip = new $zipClass(); - - // Retrieve OVERWRITE and CREATE constants from the instantiated zip class - // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP - $ro = new \ReflectionObject($objZip); - $zipOverWrite = $ro->getConstant('OVERWRITE'); - $zipCreate = $ro->getConstant('CREATE'); - - // Remove any existing file - if (file_exists($pFilename)) { - unlink($pFilename); - } - - // Try opening the ZIP file - if ($objZip->open($pFilename, $zipOverWrite) !== true) { - if ($objZip->open($pFilename, $zipCreate) !== true) { - throw new Exception("Could not open " . $pFilename . " for writing."); - } - } + $filename = $this->getTempFile($filename); + $objZip = $this->getZipArchive($filename); // Add mimetype to ZIP file //@todo Not in \ZipArchive::CM_STORE mode @@ -95,7 +74,7 @@ class ODText extends AbstractWriter implements WriterInterface // Close file if ($objZip->close() === false) { - throw new Exception("Could not close zip file $pFilename."); + throw new Exception("Could not close zip file $filename."); } $this->cleanupTempFile(); diff --git a/src/PhpWord/Writer/ODText/Base.php b/src/PhpWord/Writer/ODText/Base.php new file mode 100644 index 00000000..a1f0d315 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Base.php @@ -0,0 +1,93 @@ +writeAttribute('office:version', '1.2'); + $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); + $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); + $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); + $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); + $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); + $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); + $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); + $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); + $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); + $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); + $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); + $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); + $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); + $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); + $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); + $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); + $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); + $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); + $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); + $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); + $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); + $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); + $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); + } + + /** + * Write font faces declaration + */ + protected function writeFontFaces(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('office:font-face-decls'); + $arrFonts = array(); + $styles = Style::getStyles(); + $numFonts = 0; + if (count($styles) > 0) { + foreach ($styles as $styleName => $style) { + // Font + if ($style instanceof Font) { + $numFonts++; + $name = $style->getName(); + if (!in_array($name, $arrFonts)) { + $arrFonts[] = $name; + + // style:font-face + $xmlWriter->startElement('style:font-face'); + $xmlWriter->writeAttribute('style:name', $name); + $xmlWriter->writeAttribute('svg:font-family', $name); + $xmlWriter->endElement(); + } + } + } + } + if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { + $xmlWriter->startElement('style:font-face'); + $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index b902ffb3..327aed34 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -29,7 +29,7 @@ use PhpOffice\PhpWord\TOC; /** * ODText content part writer */ -class Content extends AbstractWriterPart +class Content extends Base { /** * Write content file to XML format @@ -51,38 +51,12 @@ class Content extends AbstractWriterPart // office:document-content $xmlWriter->startElement('office:document-content'); - $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); - $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); - $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); - $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); - $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); - $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); - $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); - $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); - $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); - $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); - $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); - $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); - $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); - $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); - $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); - $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); + $this->writeCommonRootAttributes($xmlWriter); $xmlWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms'); $xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'); $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); - $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); - $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); - $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); - $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); - $xmlWriter->writeAttribute('office:version', '1.2'); // We firstly search all fonts used $sections = $phpWord->getSections(); @@ -122,37 +96,9 @@ class Content extends AbstractWriterPart } // office:font-face-decls - $xmlWriter->startElement('office:font-face-decls'); - $arrFonts = array(); - - $styles = Style::getStyles(); - $numFonts = 0; - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - // Font - if ($style instanceof Font) { - $numFonts++; - $name = $style->getName(); - if (!in_array($name, $arrFonts)) { - $arrFonts[] = $name; - - // style:font-face - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', $name); - $xmlWriter->writeAttribute('svg:font-family', $name); - $xmlWriter->endElement(); - } - } - } - if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->endElement(); - } - } - $xmlWriter->endElement(); + $this->writeFontFaces($xmlWriter); + // office:automatic-styles $xmlWriter->startElement('office:automatic-styles'); $styles = Style::getStyles(); $numPStyles = 0; diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index e94a1fd1..106ddfc5 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -33,8 +33,8 @@ class Manifest extends AbstractWriterPart // manifest:manifest $xmlWriter->startElement('manifest:manifest'); - $xmlWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'); $xmlWriter->writeAttribute('manifest:version', '1.2'); + $xmlWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'); // manifest:file-entry $xmlWriter->startElement('manifest:file-entry'); diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Meta.php index 0df77827..8feb0d30 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Meta.php @@ -36,13 +36,13 @@ class Meta extends AbstractWriterPart // office:document-meta $xmlWriter->startElement('office:document-meta'); + $xmlWriter->writeAttribute('office:version', '1.2'); $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('office:version', '1.2'); // office:meta $xmlWriter->startElement('office:meta'); diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php index 306ee5fc..53175165 100644 --- a/src/PhpWord/Writer/ODText/Styles.php +++ b/src/PhpWord/Writer/ODText/Styles.php @@ -18,7 +18,7 @@ use PhpOffice\PhpWord\Style\Table; /** * ODText styloes part writer */ -class Styles extends AbstractWriterPart +class Styles extends Base { /** * Write Styles file to XML format @@ -40,65 +40,10 @@ class Styles extends AbstractWriterPart // Styles:Styles $xmlWriter->startElement('office:document-styles'); - $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); - $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); - $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); - $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); - $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); - $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); - $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); - $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); - $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); - $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); - $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); - $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); - $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); - $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); - $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); - $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); - $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); - $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); - $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); - $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); - $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); - $xmlWriter->writeAttribute('office:version', '1.2'); - + $this->writeCommonRootAttributes($xmlWriter); // office:font-face-decls - $xmlWriter->startElement('office:font-face-decls'); - $arrFonts = array(); - $styles = Style::getStyles(); - $numFonts = 0; - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - // Font - if ($style instanceof Font) { - $numFonts++; - $name = $style->getName(); - if (!in_array($name, $arrFonts)) { - $arrFonts[] = $name; - - // style:font-face - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', $name); - $xmlWriter->writeAttribute('svg:font-family', $name); - $xmlWriter->endElement(); - } - } - } - } - if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); + $this->writeFontFaces($xmlWriter); // office:styles $xmlWriter->startElement('office:styles'); diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index b426d570..5a489542 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -13,7 +13,6 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\DocProps; @@ -69,34 +68,13 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Save document by name * - * @param string $pFilename + * @param string $filename */ - public function save($pFilename = null) + public function save($filename = null) { if (!is_null($this->phpWord)) { - $pFilename = $this->getTempFile($pFilename); - - // Create new ZIP file and open it for writing - $zipClass = Settings::getZipClass(); - $objZip = new $zipClass(); - - // Retrieve OVERWRITE and CREATE constants from the instantiated zip class - // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP - $ro = new \ReflectionObject($objZip); - $zipOverWrite = $ro->getConstant('OVERWRITE'); - $zipCreate = $ro->getConstant('CREATE'); - - // Remove any existing file - if (file_exists($pFilename)) { - unlink($pFilename); - } - - // Try opening the ZIP file - if ($objZip->open($pFilename, $zipOverWrite) !== true) { - if ($objZip->open($pFilename, $zipCreate) !== true) { - throw new Exception("Could not open " . $pFilename . " for writing."); - } - } + $filename = $this->getTempFile($filename); + $objZip = $this->getZipArchive($filename); // Content types $this->cTypes['default'] = array( @@ -156,7 +134,7 @@ class Word2007 extends AbstractWriter implements WriterInterface // Close file if ($objZip->close() === false) { - throw new Exception("Could not close zip file $pFilename."); + throw new Exception("Could not close zip file $filename."); } $this->cleanupTempFile(); From cd2dba084891b3525db82a0663517cb942d4577e Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 8 Apr 2014 03:27:19 +0700 Subject: [PATCH 068/146] Element inheritance refinements --- src/PhpWord/Element/AbstractElement.php | 2 -- src/PhpWord/Element/Image.php | 27 ------------------------- src/PhpWord/Element/Link.php | 27 ------------------------- src/PhpWord/Element/Object.php | 27 ------------------------- src/PhpWord/Reader/AbstractReader.php | 5 ++++- src/PhpWord/Template.php | 17 +++++----------- src/PhpWord/Writer/ODText.php | 1 - src/PhpWord/Writer/ODText/Manifest.php | 1 - 8 files changed, 9 insertions(+), 98 deletions(-) diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index eabb1963..d9f9984d 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -9,7 +9,6 @@ namespace PhpOffice\PhpWord\Element; -use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\InvalidObjectException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Style; @@ -482,7 +481,6 @@ abstract class AbstractElement 'table' => array('section', 'header', 'footer'), 'footnote' => array('section', 'textrun', 'cell'), 'preservetext' => array('header', 'footer', 'cell'), - 'relationid' => array('header', 'footer', 'footnote'), 'title' => array('section'), ); // Special condition, e.g. preservetext can only exists in cell when diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index bf29220b..d49972d2 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -32,13 +32,6 @@ class Image extends AbstractElement */ private $style; - /** - * Image relation ID specific only for DOCX - * - * @var string - */ - private $rId; - /** * Is watermark * @@ -155,26 +148,6 @@ class Image extends AbstractElement return $this->style; } - /** - * Get image relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->rId; - } - - /** - * Set image relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->rId = $rId; - } - /** * Get image source * diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php index 96c66339..1cf35624 100644 --- a/src/PhpWord/Element/Link.php +++ b/src/PhpWord/Element/Link.php @@ -31,13 +31,6 @@ class Link extends AbstractElement */ private $name; - /** - * Link Relation ID - * - * @var string - */ - private $relationId; - /** * Font style * @@ -71,26 +64,6 @@ class Link extends AbstractElement return $this; } - /** - * Get Link Relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->relationId; - } - - /** - * Set Link Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->relationId = $rId; - } - /** * Get Link source * diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index f6b4161b..058117c9 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -30,13 +30,6 @@ class Object extends AbstractElement */ private $style; - /** - * Object Relation ID - * - * @var int - */ - private $relationId; - /** * Image Relation ID * @@ -84,26 +77,6 @@ class Object extends AbstractElement return $this->source; } - /** - * Get Object Relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->relationId; - } - - /** - * Set Object Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->relationId = $rId; - } - /** * Get Image Relation ID * diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index 10c864f3..cf43a858 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -90,7 +90,10 @@ abstract class AbstractReader implements ReaderInterface } catch (Exception $e) { return false; } - fclose($this->fileHandle); + if (is_resource($this->fileHandle)) { + fclose($this->fileHandle); + } + return true; } } diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 30c2ee08..b0be592d 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -222,7 +222,7 @@ class Template * @param string $blockname * @param integer $clones * @param boolean $replace - * @return null + * @return string|null */ public function cloneBlock($blockname, $clones = 1, $replace = true) { @@ -263,7 +263,6 @@ class Template * Delete a block of text * * @param string $blockname - * @param string $replacement */ public function deleteBlock($blockname) { @@ -317,7 +316,7 @@ class Template * * @param string $documentPartXML * @param string $search - * @param mixed $replace + * @param string $replace * @param integer $limit * @return string */ @@ -335,16 +334,10 @@ class Template $search = '${' . $search . '}'; } - if (!is_array($replace)) { - if (!String::isUTF8($replace)) { - $replace = utf8_encode($replace); - } - $replace = htmlspecialchars($replace); - } else { - foreach ($replace as $key => $value) { - $replace[$key] = htmlspecialchars($value); - } + if (!String::isUTF8($replace)) { + $replace = utf8_encode($replace); } + $replace = htmlspecialchars($replace); $regExpDelim = '/'; $escapedSearch = preg_quote($search, $regExpDelim); diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index e3b82f4d..4a4b1cbb 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -11,7 +11,6 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Writer\ODText\Content; use PhpOffice\PhpWord\Writer\ODText\Manifest; use PhpOffice\PhpWord\Writer\ODText\Meta; diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index 106ddfc5..b82a6041 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -9,7 +9,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; /** From 833dfea1e00adb8978d5a585fbb2052ade5b029e Mon Sep 17 00:00:00 2001 From: japonicus Date: Tue, 8 Apr 2014 17:42:01 +0100 Subject: [PATCH 069/146] Keep image aspect ratio if only 1 dimension styled If only one of image width or height is specified, then scale missing dimension to maintain the aspect ratio. --- src/PhpWord/Element/Image.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d49972d2..611b36b3 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -131,9 +131,17 @@ class Image extends AbstractElement $this->source = $source; $this->isWatermark = $isWatermark; $this->style = $this->setStyle(new ImageStyle(), $style, true); - if ($this->style->getWidth() == null && $this->style->getHeight() == null) { - $this->style->setWidth($imgData[0]); - $this->style->setHeight($imgData[1]); + $styleWidth = $this->style->getWidth(); + $styleHeight = $this->style->getHeight(); + if (!($styleWidth && $styleHeight)) { + if ($styleWidth == null && $styleHeight == null) { + $this->style->setWidth($imgData[0]); + $this->style->setHeight($imgData[1]); + } else if ($styleWidth) { + $this->style->setHeight($imgData[1] * ($styleWidth / $imgData[0])); + } else { + $this->style->setWidth($imgData[0] * ($styleHeight / $imgData[1])); + } } $this->setImageFunctions(); } From cdb3a20cb6401f140e1212a304e87b674f3f906a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 8 Apr 2014 21:16:27 +0400 Subject: [PATCH 070/146] [FIXED] Namespacing in documentation. --- docs/general.rst | 6 +++--- docs/setup.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index e1545a04..c267d87d 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -13,7 +13,7 @@ folder `__. .. code-block:: php require_once 'src/PhpWord/Autoloader.php'; - PhpOffice\PhpWord\Autoloader::register(); + \PhpOffice\PhpWord\Autoloader::register(); $phpWord = new \PhpOffice\PhpWord\PhpWord(); @@ -73,7 +73,7 @@ during development to make the resulting XML file easier to read. .. code-block:: php - PhpOffice\PhpWord\Settings::setCompatibility(false); + \PhpOffice\PhpWord\Settings::setCompatibility(false); Zip class ~~~~~~~~~ @@ -87,7 +87,7 @@ included with PHPWord. .. code-block:: php - PhpOffice\PhpWord\Settings::setZipClass(PhpOffice\PhpWord\Settings::PCLZIP); + \PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); Default font ------------ diff --git a/docs/setup.rst b/docs/setup.rst index c773756f..3c01eb94 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -53,7 +53,7 @@ invoke ``Autoloader::register``. .. code-block:: php require_once '/path/to/src/PhpWord/Autoloader.php'; - PhpOffice\PhpWord\Autoloader::register(); + \PhpOffice\PhpWord\Autoloader::register(); Using samples ------------- From 191d37b280b6a0f96359db7d7a1ce467aa86bca3 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 8 Apr 2014 21:56:18 +0400 Subject: [PATCH 071/146] Leading backslashes in global function/constant calls were removed. --- samples/Sample_01_SimpleText.php | 4 ++-- samples/Sample_02_TabStops.php | 4 ++-- samples/Sample_03_Sections.php | 4 ++-- samples/Sample_04_Textrun.php | 4 ++-- samples/Sample_05_Multicolumn.php | 4 ++-- samples/Sample_06_Footnote.php | 4 ++-- samples/Sample_07_TemplateCloneRow.php | 4 ++-- samples/Sample_08_ParagraphPagination.php | 4 ++-- samples/Sample_09_Tables.php | 4 ++-- samples/Sample_10_EastAsianFontStyle.php | 4 ++-- samples/Sample_11_ReadWord2007.php | 4 ++-- samples/Sample_12_HeaderFooter.php | 4 ++-- samples/Sample_13_Images.php | 4 ++-- samples/Sample_14_ListItem.php | 4 ++-- samples/Sample_15_Link.php | 4 ++-- samples/Sample_16_Object.php | 4 ++-- samples/Sample_17_TitleTOC.php | 6 +++--- samples/Sample_18_Watermark.php | 4 ++-- samples/Sample_19_TextBreak.php | 4 ++-- samples/Sample_20_BGColor.php | 4 ++-- samples/Sample_21_TableRowRules.php | 4 ++-- samples/Sample_22_CheckBox.php | 4 ++-- samples/Sample_23_TemplateBlock.php | 2 +- src/PhpWord/Element/Image.php | 10 ++++----- src/PhpWord/Element/Object.php | 2 +- src/PhpWord/Element/PreserveText.php | 2 +- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Writer/RTF.php | 24 ++++++++++----------- tests/PhpWord/Tests/AutoloaderTest.php | 10 ++++----- tests/PhpWord/Tests/PhpWordTest.php | 8 +++---- tests/PhpWord/Tests/Writer/ODTextTest.php | 10 ++++----- tests/PhpWord/Tests/Writer/Word2007Test.php | 8 +++---- tests/bootstrap.php | 6 +++--- 33 files changed, 87 insertions(+), 87 deletions(-) diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 4405eaeb..02b78bd7 100755 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16)); $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'spaceAfter' => 100)); @@ -48,7 +48,7 @@ $section->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 01dc7617..df2ec8b3 100755 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Ads styles @@ -36,7 +36,7 @@ $section->addText("\tCenter Aligned", NULL, 'centerTab'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index 7289fef0..4953b6a6 100755 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section @@ -29,7 +29,7 @@ $section->addFooter()->addText('Footer'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 6c13a84f..354eadfd 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Ads styles @@ -37,7 +37,7 @@ $textrun->addText(' Here is some more text. '); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 4d81766e..478a8dd0 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. ' . @@ -39,7 +39,7 @@ $section->addText('Normal paragraph again.'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 270573d9..75120088 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); \PhpOffice\PhpWord\Settings::setCompatibility(false); @@ -41,7 +41,7 @@ $footnote->addText('The reference for this is wrapped in its own line'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index 789d22f0..3049466d 100755 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $document = $phpWord->loadTemplate('resources/Sample_07_TemplateCloneRow.docx'); @@ -56,7 +56,7 @@ $document->setValue('userName#3', 'Ray'); $document->setValue('userPhone#3', '+1 428 889 775'); $name = 'Sample_07_TemplateCloneRow.docx'; -echo date('H:i:s'), " Write to Word2007 format", \EOL; +echo date('H:i:s'), " Write to Word2007 format", EOL; $document->saveAs($name); rename($name, "results/{$name}"); diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index 4b184cfd..bf1400a0 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle(array( 'align' => 'both', @@ -49,7 +49,7 @@ $section->addText('Paragraph with pageBreakBefore = true (default: false). ' . $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index d841092c..5af73fb6 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); @@ -88,7 +88,7 @@ $table->addCell(null, $cellRowContinue); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index d4ea2c4a..39f449c3 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); @@ -13,7 +13,7 @@ $section->addText('中文楷体样式测试',array('name' => '楷体', 'size' => $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index b2420a53..e5112e2e 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -4,13 +4,13 @@ include_once 'Sample_Header.php'; // Read contents $name = basename(__FILE__, '.php'); $source = "resources/{$name}.docx"; -echo date('H:i:s'), " Reading contents from `{$source}`", \EOL; +echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source); // (Re)write contents $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index a30358f2..15309041 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section @@ -64,7 +64,7 @@ $section2->addText('Some text...'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 405f653b..4ef325b8 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -24,7 +24,7 @@ $section->addImage($source); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index a7dc48ff..4cd9edea 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -48,7 +48,7 @@ $section->addListItem('List Item 7', 0, 'myOwnStyle', $listStyle, 'P-Style'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index a2e4f9e1..c4435ac0 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -22,7 +22,7 @@ $section->addLink('http://www.yahoo.com', null, 'myOwnLinkStyle'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index ec2dbce4..cb8de6db 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -17,7 +17,7 @@ $section->addObject('resources/_sheet.xls'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 87c379b2..15de531b 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -66,14 +66,14 @@ $section->addText('Text'); $section->addTitle('Subtitle 3.1.2', 3); $section->addText('Text'); -echo date('H:i:s'), " Note: Please refresh TOC manually.", \EOL; +echo date('H:i:s'), " Note: Please refresh TOC manually.", EOL; // End code // Save file $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index 96fe5c99..d0ea786a 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -18,7 +18,7 @@ $section->addText('The header reference to the current section includes a waterm $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index b594bebd..d7e11ea4 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -31,7 +31,7 @@ $section->addText('Done.'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index ed6ec320..fec40859 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); @@ -14,7 +14,7 @@ $section->addText("Compatible with font colors", array("color"=>"0000ff", "bgCol $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 6f3575cd..10ad156d 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); @@ -31,7 +31,7 @@ $section->addText("So: $"."table2->addRow(3750, array('exactHeight'=>true));"); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 3c2b64e5..89827388 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); @@ -18,7 +18,7 @@ $cell->addCheckBox('chkBox2', 'Checkbox 2'); $name = basename(__FILE__, '.php'); $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; + echo date('H:i:s'), " Write to {$writer} format", EOL; $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); $xmlWriter->save("{$name}.{$extension}"); rename("{$name}.{$extension}", "results/{$name}.{$extension}"); diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php index 168070e0..bbde5a72 100644 --- a/samples/Sample_23_TemplateBlock.php +++ b/samples/Sample_23_TemplateBlock.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $document = $phpWord->loadTemplate('resources/Sample_23_TemplateBlock.docx'); diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d49972d2..7ea28819 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -89,7 +89,7 @@ class Image extends AbstractElement if (stripos(strrev($source), strrev('.php')) === 0) { $this->isMemImage = true; } else { - $this->isMemImage = (filter_var($source, \FILTER_VALIDATE_URL) !== false); + $this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); } // Check supported types @@ -105,9 +105,9 @@ class Image extends AbstractElement } } else { $supportedTypes = array( - \IMAGETYPE_JPEG, \IMAGETYPE_GIF, - \IMAGETYPE_PNG, \IMAGETYPE_BMP, - \IMAGETYPE_TIFF_II, \IMAGETYPE_TIFF_MM + IMAGETYPE_JPEG, IMAGETYPE_GIF, + IMAGETYPE_PNG, IMAGETYPE_BMP, + IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ); if (!file_exists($source)) { throw new InvalidImageException(); @@ -124,7 +124,7 @@ class Image extends AbstractElement if (!in_array($this->imageType, $supportedTypes)) { throw new UnsupportedImageTypeException(); } - $this->imageType = \image_type_to_mime_type($this->imageType); + $this->imageType = image_type_to_mime_type($this->imageType); } // Set private properties diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 058117c9..6375cb70 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -48,7 +48,7 @@ class Object extends AbstractElement $supportedTypes = array('xls', 'doc', 'ppt', 'xlsx', 'docx', 'pptx'); $inf = pathinfo($src); - if (\file_exists($src) && in_array($inf['extension'], $supportedTypes)) { + if (file_exists($src) && in_array($inf['extension'], $supportedTypes)) { $this->source = $src; $this->style = $this->setStyle(new ImageStyle(), $style, true); return $this; diff --git a/src/PhpWord/Element/PreserveText.php b/src/PhpWord/Element/PreserveText.php index 76e860fe..12a00b0c 100644 --- a/src/PhpWord/Element/PreserveText.php +++ b/src/PhpWord/Element/PreserveText.php @@ -52,7 +52,7 @@ class PreserveText extends AbstractElement $this->fontStyle = $this->setStyle(new Font('text'), $styleFont); $this->paragraphStyle = $this->setStyle(new Paragraph(), $styleParagraph); - $matches = preg_split('/({.*?})/', $text, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + $matches = preg_split('/({.*?})/', $text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); if (isset($matches[0])) { $this->text = $matches; } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 63d26a09..ae3aae40 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -100,7 +100,7 @@ class PhpWord */ public function addSection($settings = null) { - $section = new Section(\count($this->sections) + 1, $settings); + $section = new Section(count($this->sections) + 1, $settings); $this->sections[] = $section; return $section; diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php index 2505a76d..a1ff4bc6 100755 --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -101,22 +101,22 @@ class RTF extends AbstractWriter implements WriterInterface $sRTFContent .= '\deff0'; // Set the default tab size (720 twips) $sRTFContent .= '\deftab720'; - $sRTFContent .= \PHP_EOL; + $sRTFContent .= PHP_EOL; // Set the font tbl group $sRTFContent .= '{\fonttbl'; foreach ($this->fontTable as $idx => $font) { $sRTFContent .= '{\f' . $idx . '\fnil\fcharset0 ' . $font . ';}'; } - $sRTFContent .= '}' . \PHP_EOL; + $sRTFContent .= '}' . PHP_EOL; // Set the color tbl group $sRTFContent .= '{\colortbl '; foreach ($this->colorTable as $idx => $color) { $arrColor = Drawing::htmlToRGB($color); $sRTFContent .= ';\red' . $arrColor[0] . '\green' . $arrColor[1] . '\blue' . $arrColor[2] . ''; } - $sRTFContent .= ';}' . \PHP_EOL; + $sRTFContent .= ';}' . PHP_EOL; // Set the generator - $sRTFContent .= '{\*\generator PhpWord;}' . \PHP_EOL; + $sRTFContent .= '{\*\generator PhpWord;}' . PHP_EOL; // Set the view mode of the document $sRTFContent .= '\viewkind4'; // Set the numberof bytes that follows a unicode character @@ -131,7 +131,7 @@ class RTF extends AbstractWriter implements WriterInterface $sRTFContent .= '\kerning1'; // Set the font size in half-points $sRTFContent .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); - $sRTFContent .= \PHP_EOL; + $sRTFContent .= PHP_EOL; // Body $sRTFContent .= $this->getDataContent(); @@ -392,7 +392,7 @@ class RTF extends AbstractWriter implements WriterInterface } if (!$withoutP) { - $sRTFText .= '\par' . \PHP_EOL; + $sRTFText .= '\par' . PHP_EOL; } return $sRTFText; } @@ -407,15 +407,15 @@ class RTF extends AbstractWriter implements WriterInterface $sRTFText = ''; $elements = $textrun->getElements(); if (count($elements) > 0) { - $sRTFText .= '\pard\nowidctlpar' . \PHP_EOL; + $sRTFText .= '\pard\nowidctlpar' . PHP_EOL; foreach ($elements as $element) { if ($element instanceof Text) { $sRTFText .= '{'; $sRTFText .= $this->getDataContentText($element, true); - $sRTFText .= '}' . \PHP_EOL; + $sRTFText .= '}' . PHP_EOL; } } - $sRTFText .= '\par' . \PHP_EOL; + $sRTFText .= '\par' . PHP_EOL; } return $sRTFText; } @@ -429,7 +429,7 @@ class RTF extends AbstractWriter implements WriterInterface { $this->lastParagraphStyle = ''; - return '\par' . \PHP_EOL; + return '\par' . PHP_EOL; } /** @@ -440,9 +440,9 @@ class RTF extends AbstractWriter implements WriterInterface private function getDataContentUnsupportedElement($element) { $sRTFText = ''; - $sRTFText .= '\pard\nowidctlpar' . \PHP_EOL; + $sRTFText .= '\pard\nowidctlpar' . PHP_EOL; $sRTFText .= "{$element}"; - $sRTFText .= '\par' . \PHP_EOL; + $sRTFText .= '\par' . PHP_EOL; return $sRTFText; } diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index ac2f4a78..2a021aeb 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -26,7 +26,7 @@ class AutoloaderTest extends \PHPUnit_Framework_TestCase Autoloader::register(); $this->assertContains( array('PhpOffice\\PhpWord\\Autoloader', 'autoload'), - \spl_autoload_functions() + spl_autoload_functions() ); } @@ -35,19 +35,19 @@ class AutoloaderTest extends \PHPUnit_Framework_TestCase */ public function testAutoload() { - $declared = \get_declared_classes(); - $declaredCount = \count($declared); + $declared = get_declared_classes(); + $declaredCount = count($declared); Autoloader::autoload('Foo'); $this->assertEquals( $declaredCount, - \count(get_declared_classes()), + count(get_declared_classes()), 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' . 'classes outside of the PhpOffice\\PhpWord namespace' ); // TODO change this class to the main PhpWord class when it is namespaced Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); $this->assertTrue( - \in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', \get_declared_classes()), + in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', get_declared_classes()), 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' . 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' ); diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index efef7053..8de6f808 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -53,7 +53,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $this->assertEquals(new Section(1), $phpWord->addSection()); $phpWord->addSection(); - $this->assertEquals(2, \count($phpWord->getSections())); + $this->assertEquals(2, count($phpWord->getSections())); } /** @@ -144,9 +144,9 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase */ public function testLoadTemplateException() { - $templateFqfn = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx') + $templateFqfn = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx') ); $phpWord = new PhpWord(); $phpWord->loadTemplate($templateFqfn); diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index e113c373..fad3a6c0 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -128,9 +128,9 @@ class ODTextTest extends \PHPUnit_Framework_TestCase public function testSetGetUseDiskCaching() { $object = new ODText(); - $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); + $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); $this->assertTrue($object->getUseDiskCaching()); - $this->assertEquals(\PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory()); + $this->assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory()); } /** @@ -140,9 +140,9 @@ class ODTextTest extends \PHPUnit_Framework_TestCase */ public function testSetUseDiskCachingException() { - $dir = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'foo') + $dir = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'foo') ); $object = new ODText(); diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index fe80adb0..38c2e6e7 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -169,7 +169,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $section = $phpWord->addSection(); $object = new Word2007($phpWord); - $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); + $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); $writer = new Word2007($phpWord); $writer->save('php://output'); @@ -183,9 +183,9 @@ class Word2007Test extends \PHPUnit_Framework_TestCase */ public function testSetUseDiskCachingException() { - $dir = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'foo') + $dir = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'foo') ); $object = new Word2007(); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9ccbd596..c25aeac9 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -16,11 +16,11 @@ if (!defined('PHPWORD_TESTS_BASE_DIR')) { $vendor = realpath(__DIR__ . '/../vendor'); -if (\file_exists($vendor . "/autoload.php")) { +if (file_exists($vendor . "/autoload.php")) { require $vendor . "/autoload.php"; } else { $vendor = realpath(__DIR__ . '/../../../'); - if (\file_exists($vendor . "/autoload.php")) { + if (file_exists($vendor . "/autoload.php")) { require $vendor . "/autoload.php"; } else { throw new Exception("Unable to load dependencies"); @@ -35,7 +35,7 @@ spl_autoload_register(function ($class) { $class = join(DIRECTORY_SEPARATOR, array('PhpWord', 'Tests', '_includes')) . substr($class, strlen($prefix)); $file = __DIR__ . DIRECTORY_SEPARATOR . $class . '.php'; - if (\file_exists($file)) { + if (file_exists($file)) { require_once $file; } } From f049c48c59fa3765e413187cd44d605a899e3605 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 8 Apr 2014 21:58:00 +0400 Subject: [PATCH 072/146] [FIXED] Namespacing. --- README.md | 2 +- samples/Sample_Header.php | 2 +- tests/bootstrap.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 95d5947e..8470aa90 100755 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ In this case, you will have to register the autoloader. ```php require_once 'path/to/PhpWord/src/PhpWord/Autoloader.php'; -PhpOffice\PhpWord\Autoloader::register(); +\PhpOffice\PhpWord\Autoloader::register(); ``` ## Basic usage diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index b61e415a..c6431c03 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -9,7 +9,7 @@ define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php')); define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; -PhpOffice\PhpWord\Autoloader::register(); +\PhpOffice\PhpWord\Autoloader::register(); // Return to the caller script when runs by CLI if (CLI) { diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c25aeac9..eb23221e 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -42,4 +42,4 @@ spl_autoload_register(function ($class) { }); require_once __DIR__ . "/../src/PhpWord/Autoloader.php"; -PhpOffice\PhpWord\Autoloader::register(); +\PhpOffice\PhpWord\Autoloader::register(); From 9c9f7eb7c683f2b2ff7975f4fca155099d7abb42 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Tue, 8 Apr 2014 22:00:36 +0400 Subject: [PATCH 073/146] NULLs changed to lowercase to meet PSR. --- samples/Sample_02_TabStops.php | 6 +++--- src/PhpWord/Style/Tab.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index df2ec8b3..dbed59a3 100755 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -28,9 +28,9 @@ $phpWord->addParagraphStyle('centerTab', array( $section = $phpWord->addSection(); // Add listitem elements -$section->addText("Multiple Tabs:\tOne\tTwo\tThree", NULL, 'multipleTab'); -$section->addText("Left Aligned\tRight Aligned", NULL, 'rightTab'); -$section->addText("\tCenter Aligned", NULL, 'centerTab'); +$section->addText("Multiple Tabs:\tOne\tTwo\tThree", null, 'multipleTab'); +$section->addText("Left Aligned\tRight Aligned", null, 'rightTab'); +$section->addText("\tCenter Aligned", null, 'centerTab'); // Save file $name = basename(__FILE__, '.php'); diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index c28d8923..e9c044f1 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -75,7 +75,7 @@ class Tab extends AbstractStyle * * @param string $val Defaults to 'clear' if value is not possible. * @param int $position Must be an integer; otherwise defaults to 0. - * @param string $leader Defaults to NULL if value is not possible. + * @param string $leader Defaults to null if value is not possible. */ public function __construct($val = null, $position = 0, $leader = null) { @@ -85,7 +85,7 @@ class Tab extends AbstractStyle // Default to 0 if the position is non-numeric $this->position = (is_numeric($position)) ? intval($position) : 0; - // Default to NULL if no tab leader + // Default to null if no tab leader $this->leader = (self::isLeaderType($leader)) ? $leader : null; } From 2cdad4b247db870058fa6081e05f0ebc9cb92c20 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Tue, 8 Apr 2014 16:09:31 +0700 Subject: [PATCH 074/146] Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table --- CHANGELOG.md | 7 +- samples/resources/Sample_11_ReadWord2007.docx | Bin 22104 -> 69796 bytes src/PhpWord/DocumentProperties.php | 24 +- src/PhpWord/Element/AbstractElement.php | 27 +- src/PhpWord/Element/Footnote.php | 6 +- src/PhpWord/Element/Image.php | 4 +- src/PhpWord/Element/ListItem.php | 3 +- src/PhpWord/Element/Object.php | 4 +- src/PhpWord/Element/Table.php | 3 +- src/PhpWord/Footnote.php | 108 ++- src/PhpWord/IOFactory.php | 10 +- src/PhpWord/Media.php | 18 +- src/PhpWord/PhpWord.php | 6 +- src/PhpWord/Reader/AbstractReader.php | 4 +- src/PhpWord/Reader/Word2007.php | 907 ++++++++++-------- src/PhpWord/Shared/XMLReader.php | 54 +- src/PhpWord/Shared/ZipArchive.php | 57 +- src/PhpWord/Style.php | 6 +- src/PhpWord/TOC.php | 4 +- src/PhpWord/Writer/Word2007.php | 18 +- src/PhpWord/Writer/Word2007/Base.php | 4 +- tests/PhpWord/Tests/FootnoteTest.php | 2 +- tests/PhpWord/Tests/MediaTest.php | 2 +- tests/PhpWord/Tests/StyleTest.php | 2 +- tests/PhpWord/Tests/TOCTest.php | 2 +- 25 files changed, 762 insertions(+), 520 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc43822b..d5e043b5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,10 +25,9 @@ This release marked heavy refactorings on internal code structure with the creat - CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 - Link: Ability to add link in header/footer - @ivanlanin GH-187 - Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 -- Media: Add `Media::reset()` to reset all media data - @juzi GH-19 -- Style: Add `Style::reset()` to reset all styles -- Footnote: Add `Footnote::reset()` to reset all footnotes -- TOC: Add `TOC::reset()` to reset all TOC +- Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 +- General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 +- Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table - @ivanlanin ### Bugfixes diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index fe8ec7acae8a53e80cf6219fed8b439465c7cea8..2143c628c5132f5948c339538bef2c2fabdab545 100644 GIT binary patch delta 62691 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�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 XOY%Ym$3;d0Ljn{1Yy3^&AO8OV3dA8r diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index b1f02275..f41ae421 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -138,7 +138,7 @@ class DocumentProperties * Set Creator * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCreator($pValue = '') { @@ -160,7 +160,7 @@ class DocumentProperties * Set Last Modified By * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setLastModifiedBy($pValue = '') { @@ -182,7 +182,7 @@ class DocumentProperties * Set Created * * @param int $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCreated($pValue = null) { @@ -207,7 +207,7 @@ class DocumentProperties * Set Modified * * @param int $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setModified($pValue = null) { @@ -232,7 +232,7 @@ class DocumentProperties * Set Title * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setTitle($pValue = '') { @@ -254,7 +254,7 @@ class DocumentProperties * Set Description * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setDescription($pValue = '') { @@ -276,7 +276,7 @@ class DocumentProperties * Set Subject * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setSubject($pValue = '') { @@ -298,7 +298,7 @@ class DocumentProperties * Set Keywords * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setKeywords($pValue = '') { @@ -320,7 +320,7 @@ class DocumentProperties * Set Category * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCategory($pValue = '') { @@ -342,7 +342,7 @@ class DocumentProperties * Set Company * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCompany($pValue = '') { @@ -364,7 +364,7 @@ class DocumentProperties * Set Manager * * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setManager($pValue = '') { @@ -432,7 +432,7 @@ class DocumentProperties * 's': String * 'd': Date/Time * 'b': Boolean - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null) { diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index d9f9984d..8ee75b90 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -59,7 +59,7 @@ abstract class AbstractElement * * @var string */ - private $docPart = 'section'; + protected $docPart = 'section'; /** * Document part Id @@ -70,7 +70,7 @@ abstract class AbstractElement * * @var integer */ - private $docPartId = 1; + protected $docPartId = 1; /** * Elements collection @@ -84,7 +84,7 @@ abstract class AbstractElement * * @var int */ - private $relationId; + protected $relationId; /** * Add text element @@ -144,8 +144,8 @@ abstract class AbstractElement $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); $link->setDocPart($this->getDocPart(), $this->getDocPartId()); - $rID = Media::addElement($elementDocPart, 'link', $linkSrc); - $link->setRelationId($rID); + $rId = Media::addElement($elementDocPart, 'link', $linkSrc); + $link->setRelationId($rId); $this->elements[] = $link; return $link; @@ -271,8 +271,8 @@ abstract class AbstractElement $image = new Image($src, $style, $isWatermark); $image->setDocPart($this->getDocPart(), $this->getDocPartId()); - $rID = Media::addElement($elementDocPart, 'image', $src, $image); - $image->setRelationId($rID); + $rId = Media::addElement($elementDocPart, 'image', $src, $image); + $image->setRelationId($rId); $this->elements[] = $image; return $image; } @@ -301,10 +301,10 @@ abstract class AbstractElement $ext = substr($ext, 0, -1); } $icon = realpath(__DIR__ . "/../_staticDocParts/_{$ext}.png"); - $rID = Media::addElement($elementDocPart, 'object', $src); - $object->setRelationId($rID); - $rIDimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); - $object->setImageRelationId($rIDimg); + $rId = Media::addElement($elementDocPart, 'object', $src); + $object->setRelationId($rId); + $rIdimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); + $object->setImageRelationId($rIdimg); $this->elements[] = $object; return $object; } else { @@ -323,9 +323,10 @@ abstract class AbstractElement $this->checkValidity('footnote'); $footnote = new FootnoteElement($paragraphStyle); - $refID = FootnoteCollection::addFootnoteElement($footnote); + $rId = FootnoteCollection::addFootnoteElement($footnote); + $footnote->setDocPart('footnote', $this->getDocPartId()); - $footnote->setRelationId($refID); + $footnote->setRelationId($rId); $this->elements[] = $footnote; return $footnote; diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index e79e9c79..d35dd548 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -59,12 +59,12 @@ class Footnote extends AbstractElement /** * Set Footnote Reference ID * - * @param int $refId + * @param int $rId * @deprecated 0.9.2 * @codeCoverageIgnore */ - public function setReferenceId($refId) + public function setReferenceId($rId) { - $this->setRelationId($refId); + $this->setRelationId($rId); } } diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index d49972d2..92e93f1f 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -80,8 +80,8 @@ class Image extends AbstractElement * @param string $source * @param mixed $style * @param boolean $isWatermark - * @throws \PhpOffice\PhpWord\Exception\InvalidImageException - * @throws \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException + * @throws InvalidImageException + * @throws UnsupportedImageTypeException */ public function __construct($source, $style = null, $isWatermark = false) { diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 64ac149d..5d19097e 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -9,6 +9,7 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Style\ListItem as ListItemStyle; /** @@ -26,7 +27,7 @@ class ListItem extends AbstractElement /** * Textrun * - * @var \PhpOffice\PhpWord\Element\Text + * @var Text */ private $textObject; diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index 058117c9..49a0ca8a 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -26,7 +26,7 @@ class Object extends AbstractElement /** * Image Style * - * @var \PhpOffice\PhpWord\Style\Image + * @var ImageStyle */ private $style; @@ -60,7 +60,7 @@ class Object extends AbstractElement /** * Get Image style * - * @return \PhpOffice\PhpWord\Style\Image + * @return ImageStyle */ public function getStyle() { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 0c8d494d..90913582 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -10,6 +10,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Element\Row; +use PhpOffice\PhpWord\Element\Cell; use PhpOffice\PhpWord\Style\Table as TableStyle; /** @@ -70,7 +71,7 @@ class Table extends AbstractElement * * @param int $width * @param mixed $style - * @return \PhpOffice\PhpWord\Element\Cell + * @return Cell */ public function addCell($width = null, $style = null) { diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 9b11518b..2e38a962 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -13,65 +13,133 @@ use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Element\Footnote as FootnoteElement; /** - * Footnote + * Footnote collection */ class Footnote { /** - * Footnote elements + * Elements * * @var array */ private static $elements = array(); + /** + * Add new element + * + * @param FootnoteElement $footnote + * @return integer Reference ID + * @since 0.9.2 + */ + public static function addElement(FootnoteElement $footnote) + { + $rId = self::countElements() + 1; + self::$elements[$rId] = $footnote; + + return $rId; + } + + /** + * Set element + * + * @param integer $index + * @param FootnoteElement $footnote + * @since 0.9.2 + */ + public static function setElement($index, FootnoteElement $footnote) + { + self::$elements[$index] = $footnote; + } + + /** + * Get element by index + * + * @return FootnoteElement + * @since 0.9.2 + */ + public static function getElement($index) + { + if (array_key_exists($index, self::$elements)) { + return self::$elements[$index]; + } else { + return null; + } + } + + /** + * Get elements + * + * @return array + * @since 0.9.2 + */ + public static function getElements() + { + return self::$elements; + } + + /** + * Get element count + * + * @return integer + * @since 0.9.2 + */ + public static function countElements() + { + return count(self::$elements); + } + + /** + * Reset elements + * + * @since 0.9.2 + */ + public static function resetElements() + { + self::$elements = array(); + } + /** * Add new footnote * * @param FootnoteElement $footnote - * @return int Reference ID + * @return integer Reference ID + * @deprecated 0.9.2 + * @codeCoverageIgnore */ public static function addFootnoteElement(FootnoteElement $footnote) { - $refID = self::countFootnoteElements() + 1; - - self::$elements[] = $footnote; - - return $refID; + return self::addElement($footnote); } /** * Get Footnote Elements * * @return array + * @deprecated 0.9.2 + * @codeCoverageIgnore */ public static function getFootnoteElements() { - return self::$elements; + return self::getElements(); } /** * Get Footnote Elements Count * - * @return int + * @return integer + * @deprecated 0.9.2 + * @codeCoverageIgnore */ public static function countFootnoteElements() { - return count(self::$elements); - } - - /** - * Reset footer elements - */ - public static function reset() - { - self::$elements = array(); + return self::countElements(); } /** * Add new Footnote Link Element * * @param string $linkSrc - * @return int Reference ID + * @return integer Reference ID * @deprecated 0.9.2 * @codeCoverageIgnore */ diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index 7b32ef44..ade4398e 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -10,6 +10,8 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Writer\WriterInterface; +use PhpOffice\PhpWord\Reader\ReaderInterface; /** * IO factory @@ -19,9 +21,9 @@ abstract class IOFactory /** * Create new writer * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @param string $name - * @return \PhpOffice\PhpWord\Writer\WriterInterface + * @return WriterInterface * @throws Exception */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') @@ -38,7 +40,7 @@ abstract class IOFactory * Create new reader * * @param string $name - * @return \PhpOffice\PhpWord\Reader\ReaderInterface + * @return ReaderInterface * @throws Exception */ public static function createReader($name = 'Word2007') @@ -56,7 +58,7 @@ abstract class IOFactory * * @param string $filename The name of the file * @param string $readerName - * @return \PhpOffice\PhpWord + * @return PhpWord */ public static function load($filename, $readerName = 'Word2007') { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 921fc154..a8822970 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -13,7 +13,7 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Element\Image; /** - * Media + * Media collection */ class Media { @@ -39,7 +39,7 @@ class Media // Assign unique media Id and initiate media container if none exists $mediaId = md5($container . $source); if (!array_key_exists($container, self::$elements)) { - self::$elements[$container]= array(); + self::$elements[$container] = array(); } // Add media if not exists or point to existing media @@ -47,7 +47,7 @@ class Media $mediaCount = self::countElements($container); $mediaTypeCount = self::countElements($container, $mediaType); $mediaData = array(); - $relId = ++$mediaCount; + $rId = ++$mediaCount; $target = null; $mediaTypeCount++; @@ -57,15 +57,15 @@ class Media throw new Exception('Image object not assigned.'); } $isMemImage = $image->getIsMemImage(); - $ext = $image->getImageExtension(); - $mediaData['imageExtension'] = $ext; + $extension = $image->getImageExtension(); + $mediaData['imageExtension'] = $extension; $mediaData['imageType'] = $image->getImageType(); if ($isMemImage) { $mediaData['isMemImage'] = true; $mediaData['createFunction'] = $image->getImageCreateFunction(); $mediaData['imageFunction'] = $image->getImageFunction(); } - $target = "media/{$container}_image{$mediaTypeCount}.{$ext}"; + $target = "media/{$container}_image{$mediaTypeCount}.{$extension}"; // Objects } elseif ($mediaType == 'object') { $file = "oleObject{$mediaTypeCount}.bin"; @@ -78,9 +78,9 @@ class Media $mediaData['source'] = $source; $mediaData['target'] = $target; $mediaData['type'] = $mediaType; - $mediaData['rID'] = $relId; + $mediaData['rID'] = $rId; self::$elements[$container][$mediaId] = $mediaData; - return $relId; + return $rId; } else { return self::$elements[$container][$mediaId]['rID']; } @@ -153,7 +153,7 @@ class Media /** * Reset media elements */ - public static function reset() + public static function resetElements() { self::$elements = array(); } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 63d26a09..29b6472f 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -82,8 +82,8 @@ class PhpWord /** * Set document properties object * - * @param \PhpOffice\PhpWord\DocumentProperties $documentProperties - * @return \PhpOffice\PhpWord\PhpWord + * @param DocumentProperties $documentProperties + * @return self */ public function setDocumentProperties(DocumentProperties $documentProperties) { @@ -217,7 +217,7 @@ class PhpWord /** * Get all sections * - * @return \PhpOffice\PhpWord\Element\Section[] + * @return Section[] */ public function getSections() { diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index cf43a858..99db598c 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -47,7 +47,7 @@ abstract class AbstractReader implements ReaderInterface * Set read data only * * @param bool $pValue - * @return \PhpOffice\PhpWord\Reader\ReaderInterface + * @return self */ public function setReadDataOnly($pValue = true) { @@ -60,7 +60,7 @@ abstract class AbstractReader implements ReaderInterface * * @param string $pFilename * @return resource - * @throws \PhpOffice\PhpWord\Exception\Exception + * @throws Exception */ protected function openFile($pFilename) { diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index afd68eda..422258f2 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,6 +11,7 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\DocumentProperties; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLReader; @@ -18,6 +19,10 @@ use PhpOffice\PhpWord\Element\Section; /** * Reader for Word2007 + * + * @since 0.9.2 + * @todo title, list, watermark, checkbox, toc + * @todo Partly done: image, object */ class Word2007 extends AbstractReader implements ReaderInterface { @@ -33,239 +38,154 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @var array */ - private $partRels = array('document' => array(), 'footnotes' => array()); - - /** - * Current active part document|footnotes|headerx|footerx - * - * @var string - */ - private $activePart = 'document'; - - /** - * Can the current ReaderInterface read the file? - * - * @param string $fileName - * @return bool - * @throws Exception - */ - public function canRead($fileName) - { - // Check if file exists - if (!file_exists($fileName)) { - throw new Exception("Could not open {$fileName} for reading! File does not exist."); - } - - $return = false; - // Load file - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); - if ($zip->open($fileName) === true) { - // check if it is an OOXML archive - $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); - if ($rels !== false) { - foreach ($rels->Relationship as $rel) { - switch ($rel["Type"]) { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": - if (basename($rel["Target"]) == 'document.xml') { - $return = true; - } - break; - - } - } - } - $zip->close(); - } - - return $return; - } - - /** - * Get zip content - * - * @param mixed $archive - * @param string $fileName - * @param bool $removeNamespace - * @return string - */ - public function getFromZipArchive($archive, $fileName = '', $removeNamespace = false) - { - // Root-relative paths - // if (strpos($fileName, '//') !== false) { - // $fileName = substr($fileName, strpos($fileName, '//') + 1); - // } - // $fileName = realpath($fileName); - - // Apache POI fixes - $contents = $archive->getFromName($fileName); - if ($contents === false) { - $contents = $archive->getFromName(substr($fileName, 1)); - } - - // Remove namespaces from elements and attributes name - if ($removeNamespace) { - $contents = preg_replace('~( array(), 'document' => array()); /** * Loads PhpWord from file * - * @param string $fileName + * @param string $filename * @return PhpWord|null */ - public function load($fileName) + public function load($filename) { - // Check if file exists and can be read - if (!$this->canRead($fileName)) { - return null; - } - - // Initialisations $this->phpWord = new PhpWord(); - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); - $zip->open($fileName); - // Read document relationships - $this->readPartRels($fileName, 'document'); + $this->readRelationships($filename); - // Read properties and documents - $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); - foreach ($rels->Relationship as $rel) { - switch ($rel["Type"]) { - // Core properties - case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $xmlCore->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/"); - $xmlCore->registerXPathNamespace("dcterms", "http://purl.org/dc/terms/"); - $xmlCore->registerXPathNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); - $docProps = $this->phpWord->getDocumentProperties(); - $docProps->setCreator((string)self::arrayItem($xmlCore->xpath("dc:creator"))); - $docProps->setLastModifiedBy((string)self::arrayItem($xmlCore->xpath("cp:lastModifiedBy"))); - $docProps->setCreated(strtotime(self::arrayItem($xmlCore->xpath("dcterms:created")))); - $docProps->setModified(strtotime(self::arrayItem($xmlCore->xpath("dcterms:modified")))); - $docProps->setTitle((string)self::arrayItem($xmlCore->xpath("dc:title"))); - $docProps->setDescription((string)self::arrayItem($xmlCore->xpath("dc:description"))); - $docProps->setSubject((string)self::arrayItem($xmlCore->xpath("dc:subject"))); - $docProps->setKeywords((string)self::arrayItem($xmlCore->xpath("cp:keywords"))); - $docProps->setCategory((string)self::arrayItem($xmlCore->xpath("cp:category"))); - } + // Read main relationship + foreach ($this->rels['main'] as $rId => $rel) { + switch ($rel['type']) { + + case 'officeDocument': + $this->readDocument($filename, $rel['target']); break; - // Extended properties - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $docProps = $this->phpWord->getDocumentProperties(); - if (isset($xmlCore->Company)) { - $docProps->setCompany((string)$xmlCore->Company); - } - if (isset($xmlCore->Manager)) { - $docProps->setManager((string)$xmlCore->Manager); - } - } + + case 'core-properties': + $mapping = array( + 'dc:creator' => 'setCreator', + 'dc:title' => 'setTitle', + 'dc:description' => 'setDescription', + 'dc:subject' => 'setSubject', + 'cp:keywords' => 'setKeywords', + 'cp:category' => 'setCategory', + 'cp:lastModifiedBy' => 'setLastModifiedBy', + 'dcterms:created' => 'setCreated', + 'dcterms:modified' => 'setModified', + ); + $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); + $this->readDocProps($filename, $rel['target'], $mapping, $callbacks); break; - // Custom properties - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $docProps = $this->phpWord->getDocumentProperties(); - foreach ($xmlCore as $xmlProperty) { - $cellDataOfficeAttributes = $xmlProperty->attributes(); - if (isset($cellDataOfficeAttributes['name'])) { - $propertyName = (string)$cellDataOfficeAttributes['name']; - $cellDataOfficeChildren = $xmlProperty->children("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); - $attributeType = $cellDataOfficeChildren->getName(); - $attributeValue = (string)$cellDataOfficeChildren->{$attributeType}; - $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); - $attributeType = DocumentProperties::convertPropertyType($attributeType); - $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); - } - } - } + + case 'extended-properties': + $mapping = array('Company' => 'setCompany', 'Manager' => 'setManager'); + $this->readDocProps($filename, $rel['target'], $mapping); + break; + + case 'custom-properties': + $this->readDocPropsCustom($filename, $rel['target']); break; } } - // Read document - $this->readDocument($fileName, 'word/document.xml'); - // Read document relationships - foreach ($this->partRels['document'] as $rId => $rel) { - if ($rel['type'] == 'styles') { - $this->readStyles($fileName, 'word/' . $rel['target']); + foreach ($this->rels['document'] as $rId => $rel) { + switch ($rel['type']) { + + case 'styles': + $this->readStyles($filename, $rel['target']); + break; + + case 'footnotes': + $this->readFootnotes($filename, $rel['target']); + break; } } - $zip->close(); return $this->phpWord; } /** - * Read _rels/$partName.xml.rels + * Read all relationship files * - * @param string $fileName - * @param string $partName document|footnotes|headerx|footerx + * @param string $filename */ - private function readPartRels($fileName, $partName) + private function readRelationships($filename) + { + // _rels/.rels + $this->rels['main'] = $this->getRels($filename, '_rels/.rels'); + + // word/_rels/*.xml.rels + $wordRelsPath = 'word/_rels/'; + $zipClass = Settings::getZipClass(); + $zip = new $zipClass(); + if ($zip->open($filename) === true) { + for ($i = 0; $i < $zip->numFiles; $i++) { + $xmlFile = $zip->getNameIndex($i); + if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath) { + $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile)); + $this->rels[$docPart] = $this->getRels($filename, $xmlFile, 'word/'); + } + } + $zip->close(); + } + } + + /** + * Read core and extended document properties + * + * @param string $filename + * @param string $xmlFile + * @param array $mapping + * @param array $callbacks + */ + private function readDocProps($filename, $xmlFile, $mapping, $callbacks = array()) { - $relPrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; $xmlReader = new XMLReader(); - $response = $xmlReader->getDomFromZip($fileName, "word/_rels/{$partName}.xml.rels"); - if ($response) { - $rels = $xmlReader->getElements('*'); - foreach ($rels as $rel) { - $this->partRels[$partName][$rel->getAttribute('Id')] = array( - 'type' => str_replace($relPrefix, '', $rel->getAttribute('Type')), - 'target' => $rel->getAttribute('Target'), - ); + $xmlReader->getDomFromZip($filename, $xmlFile); + $docProps = $this->phpWord->getDocumentProperties(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $nodeName = $node->nodeName; + if (!array_key_exists($nodeName, $mapping)) { + continue; + } + $method = $mapping[$nodeName]; + $value = $node->nodeValue == '' ? null : $node->nodeValue; + if (array_key_exists($nodeName, $callbacks)) { + $value = $callbacks[$nodeName]($value); + } + if (method_exists($docProps, $method)) { + $docProps->$method($value); + } } } } /** - * Read styles.xml + * Read custom document properties * - * @param string $fileName + * @param string $filename * @param string $xmlFile */ - private function readStyles($fileName, $xmlFile) + private function readDocPropsCustom($filename, $xmlFile) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($fileName, $xmlFile); + $xmlReader->getDomFromZip($filename, $xmlFile); + $docProps = $this->phpWord->getDocumentProperties(); - $nodes = $xmlReader->getElements('w:style'); + $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { - $type = $xmlReader->getAttribute($node, 'w:type'); - $name = $xmlReader->getAttribute($node, 'w:styleId'); - if (is_null($name)) { - $name = $xmlReader->getAttribute('w:name', 'w:val', $node); - } - $default = ($xmlReader->getAttribute($node, 'w:default') == 1); - if ($type == 'paragraph') { - $pStyle = $this->readWpPr($xmlReader, $node); - $fStyle = $this->readWrPr($xmlReader, $node); - if (empty($fStyle)) { - $this->phpWord->addParagraphStyle($name, $pStyle); - } else { - $this->phpWord->addFontStyle($name, $fStyle, $pStyle); - } - } elseif ($type == 'character') { - $fStyle = $this->readWrPr($xmlReader, $node); - if (!empty($fStyle)) { - $this->phpWord->addFontStyle($name, $fStyle); - } - } elseif ($type == 'table') { - $tStyle = $this->readWtblPr($xmlReader, $node); - if (!empty($tStyle)) { - $this->phpWord->addTableStyle($name, $tStyle); - } - } + $nodeName = $node->nodeName; + $propertyName = $xmlReader->getAttribute('name', $node); + $attributeNode = $xmlReader->getElement('*', $node); + $attributeType = $attributeNode->nodeName; + $attributeValue = $attributeNode->nodeValue; + $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); + $attributeType = DocumentProperties::convertPropertyType($attributeType); + $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); } } } @@ -273,38 +193,89 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read document.xml * - * @param string $fileName + * @param string $filename * @param string $xmlFile */ - private function readDocument($fileName, $xmlFile) + private function readDocument($filename, $xmlFile) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($fileName, $xmlFile); + $xmlReader->getDomFromZip($filename, $xmlFile); $nodes = $xmlReader->getElements('w:body/*'); if ($nodes->length > 0) { $section = $this->phpWord->addSection(); foreach ($nodes as $node) { - if ($node->nodeName == 'w:p') { // Paragraph - if ($xmlReader->getAttribute('w:r/w:br', 'w:type', $node) == 'page') { - $section->addPageBreak(); // PageBreak - } else { - $this->readWp($xmlReader, $node, $section); - } - // Section properties - if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { - $settingsNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); - $settings = $this->readWsectPr($xmlReader, $settingsNode); + switch ($node->nodeName) { + case 'w:p': // Paragraph + if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') { + $section->addPageBreak(); // PageBreak + } else { + $this->readParagraph($xmlReader, $node, $section, 'document'); + } + // Section properties + if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { + $settingsNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); + $settings = $this->readSectionStyle($xmlReader, $settingsNode); + $section->setSettings($settings); + $this->readHeaderFooter($filename, $settings, $section); + $section = $this->phpWord->addSection(); + } + break; + case 'w:tbl': // Table + $this->readTable($xmlReader, $node, $section, 'document'); + break; + case 'w:sectPr': // Last section + $settings = $this->readSectionStyle($xmlReader, $node); $section->setSettings($settings); - $this->readHeaderFooter($fileName, $settings, $section); - $section = $this->phpWord->addSection(); - } - } elseif ($node->nodeName == 'w:tbl') { // Table - $this->readWtbl($xmlReader, $node, $section); - } elseif ($node->nodeName == 'w:sectPr') { // Last section - $settings = $this->readWsectPr($xmlReader, $node); - $section->setSettings($settings); - $this->readHeaderFooter($fileName, $settings, $section); + $this->readHeaderFooter($filename, $settings, $section); + break; + } + } + } + } + + /** + * Read styles.xml + * + * @param string $filename + * @param string $xmlFile + */ + private function readStyles($filename, $xmlFile) + { + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($filename, $xmlFile); + + $nodes = $xmlReader->getElements('w:style'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $type = $xmlReader->getAttribute('w:type', $node); + $name = $xmlReader->getAttribute('w:styleId', $node); + if (is_null($name)) { + $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); + } + $default = ($xmlReader->getAttribute('w:default', $node) == 1); + switch ($type) { + case 'paragraph': + $pStyle = $this->readParagraphStyle($xmlReader, $node); + $fStyle = $this->readFontStyle($xmlReader, $node); + if (empty($fStyle)) { + $this->phpWord->addParagraphStyle($name, $pStyle); + } else { + $this->phpWord->addFontStyle($name, $fStyle, $pStyle); + } + break; + case 'character': + $fStyle = $this->readFontStyle($xmlReader, $node); + if (!empty($fStyle)) { + $this->phpWord->addFontStyle($name, $fStyle); + } + break; + case 'table': + $tStyle = $this->readTableStyle($xmlReader, $node); + if (!empty($tStyle)) { + $this->phpWord->addTableStyle($name, $tStyle); + } + break; } } } @@ -313,86 +284,132 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read header footer * - * @param string $fileName + * @param string $filename * @param array $settings * @param Section $section */ - private function readHeaderFooter($fileName, $settings, &$section) + private function readHeaderFooter($filename, $settings, &$section) { - if (is_array($settings) && array_key_exists('headerFooter', $settings)) { - foreach ($settings['headerFooter'] as $rId => $headerFooter) { - if (array_key_exists($rId, $this->partRels['document'])) { - $target = $this->partRels['document'][$rId]['target']; - $xmlFile = 'word/' . $target; - $method = 'add' . $headerFooter['method']; - $type = $headerFooter['type']; - $object = $section->$method($type); - - $this->activePart = str_replace('.xml', '', $target); - $this->readPartRels($fileName, $this->activePart); + if (is_array($settings) && array_key_exists('hf', $settings)) { + foreach ($settings['hf'] as $rId => $hfSetting) { + if (array_key_exists($rId, $this->rels['document'])) { + list($hfType, $xmlFile, $docPart) = array_values($this->rels['document'][$rId]); + $method = "add{$hfType}"; + $hfObject = $section->$method($hfSetting['type']); + // Read header/footer content $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($fileName, $xmlFile); + $xmlReader->getDomFromZip($filename, $xmlFile); $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { - if ($node->nodeName == 'w:p') { // Paragraph - $this->readWp($xmlReader, $node, $object); - } elseif ($node->nodeName == 'w:tbl') { // Table - $this->readWtbl($xmlReader, $node, $object); + switch ($node->nodeName) { + + case 'w:p': // Paragraph + $this->readParagraph($xmlReader, $node, $hfObject, $docPart); + break; + + case 'w:tbl': // Table + $this->readTable($xmlReader, $node, $hfObject, $docPart); + break; } } } } } } - $this->activePart = 'document'; + } + + /** + * Read footnotes.xml + * + * @param string $filename + * @param string $xmlFile + */ + private function readFootnotes($filename, $xmlFile) + { + $footnotes = Footnote::getElements(); + + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($filename, $xmlFile); + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $id = $xmlReader->getAttribute('w:id', $node); + $type = $xmlReader->getAttribute('w:type', $node); + + // Avoid w:type "separator" and "continuationSeparator" + // Only look for without w:type attribute + if (is_null($type) && array_key_exists($id, $footnotes)) { + $footnote = $footnotes[$id]; + $pNodes = $xmlReader->getElements('w:p/*', $node); + foreach ($pNodes as $pNode) { + $this->readRun($xmlReader, $pNode, $footnote, 'footnotes'); + } + Footnote::setElement($id, $footnote); + } + } + } } /** * Read w:p * - * @param mixed $container + * @param mixed $parent + * @param string $docPart + * * @todo Get font style for preserve text */ - private function readWp(XMLReader $xmlReader, \DOMNode $domNode, &$container) + private function readParagraph(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart) { // Paragraph style $pStyle = null; if ($xmlReader->elementExists('w:pPr', $domNode)) { - $pStyle = $this->readWpPr($xmlReader, $domNode); + $pStyle = $this->readParagraphStyle($xmlReader, $domNode); } - // Content - if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { // Preserve text + // PreserveText + if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { + $ignoreText = false; $textContent = ''; - $fStyle = $this->readWrPr($xmlReader, $domNode); + $fStyle = $this->readFontStyle($xmlReader, $domNode); $nodes = $xmlReader->getElements('w:r', $domNode); foreach ($nodes as $node) { $instrText = $xmlReader->getValue('w:instrText', $node); + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ($fldCharType == 'begin') { + $ignoreText = true; + } elseif ($fldCharType == 'end') { + $ignoreText = false; + } + } if (!is_null($instrText)) { $textContent .= '{' . $instrText . '}'; } else { - $textContent .= $xmlReader->getValue('w:t', $node); + if ($ignoreText === false) { + $textContent .= $xmlReader->getValue('w:t', $node); + } } } - $container->addPreserveText($textContent, $fStyle, $pStyle); - } else { // Text and TextRun + $parent->addPreserveText($textContent, $fStyle, $pStyle); + + // Text and TextRun + } else { $runCount = $xmlReader->countElements('w:r', $domNode); $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); $runLinkCount = $runCount + $linkCount; if ($runLinkCount == 0) { - $container->addTextBreak(null, $pStyle); + $parent->addTextBreak(null, $pStyle); } else { if ($runLinkCount > 1) { - $textContainer = &$container->addTextRun($pStyle); - $pStyle = null; + $textContainer = &$parent->addTextRun($pStyle); } else { - $textContainer = &$container; + $textContainer = &$parent; } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $this->readWr($xmlReader, $node, $textContainer, $pStyle); + $this->readRun($xmlReader, $node, $textContainer, $docPart, $pStyle); } } } @@ -401,52 +418,83 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read w:r * - * @param mixed $container + * @param mixed $parent + * @param string $docPart * @param mixed $pStyle + * + * @todo Footnote paragraph style */ - private function readWr(XMLReader $xmlReader, \DOMNode $domNode, &$container, $pStyle = null) + private function readRun(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart, $pStyle = null) { if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { return; } - $fStyle = $this->readWrPr($xmlReader, $domNode); + $fStyle = $this->readFontStyle($xmlReader, $domNode); + + // Link if ($domNode->nodeName == 'w:hyperlink') { - $rId = $xmlReader->getAttribute($domNode, 'r:id'); + $rId = $xmlReader->getAttribute('r:id', $domNode); $textContent = $xmlReader->getValue('w:r/w:t', $domNode); - if (array_key_exists($this->activePart, $this->partRels)) { - if (array_key_exists($rId, $this->partRels[$this->activePart])) { - $linkSource = $this->partRels[$this->activePart][$rId]['target']; - } + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $parent->addLink($target, $textContent, $fStyle, $pStyle); } - $container->addLink($linkSource, $textContent, $fStyle, $pStyle); } else { - $textContent = $xmlReader->getValue('w:t', $domNode); - $container->addText($textContent, $fStyle, $pStyle); + // Footnote + if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { + $parent->addFootnote(); + + // Image + } elseif ($xmlReader->elementExists('w:pict', $domNode)) { + $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $textContent = ""; + $parent->addText($textContent, $fStyle, $pStyle); + } + + // Object + } elseif ($xmlReader->elementExists('w:object', $domNode)) { + $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject'); + $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $textContent = ""; + $parent->addText($textContent, $fStyle, $pStyle); + } + + // TextRun + } else { + $textContent = $xmlReader->getValue('w:t', $domNode); + $parent->addText($textContent, $fStyle, $pStyle); + } } } /** * Read w:tbl * - * @param mixed $container + * @param mixed $parent + * @param string $docPart */ - private function readWtbl(XMLReader $xmlReader, \DOMNode $domNode, &$container) + private function readTable(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart) { // Table style $tblStyle = null; if ($xmlReader->elementExists('w:tblPr', $domNode)) { - $tblStyle = $this->readWtblPr($xmlReader, $domNode); + $tblStyle = $this->readTableStyle($xmlReader, $domNode); } - $table = $container->addTable($tblStyle); + $table = $parent->addTable($tblStyle); $tblNodes = $xmlReader->getElements('*', $domNode); foreach ($tblNodes as $tblNode) { $tblNodeName = $tblNode->nodeName; if ($tblNode->nodeName == 'w:tblGrid') { // Column // @todo Do something with table columns + } elseif ($tblNode->nodeName == 'w:tr') { // Row - $rowHeight = $xmlReader->getAttribute('w:trPr/w:trHeight', 'w:val', $tblNode); - $rowHRule = $xmlReader->getAttribute('w:trPr/w:trHeight', 'w:hRule', $tblNode); + $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); + $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); $rowHRule = $rowHRule == 'exact' ? true : false; $rowStyle = array( 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), @@ -459,21 +507,19 @@ class Word2007 extends AbstractReader implements ReaderInterface foreach ($rowNodes as $rowNode) { if ($rowNode->nodeName == 'w:trPr') { // Row style // @todo Do something with row style + } elseif ($rowNode->nodeName == 'w:tc') { // Cell - $cellWidth = $xmlReader->getAttribute('w:tcPr/w:tcW', 'w:w', $rowNode); + $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; if ($xmlReader->elementExists('w:tcPr', $rowNode)) { - $cellStyle = $this->readWtcPr( - $xmlReader, - $xmlReader->getElement('w:tcPr', $rowNode) - ); + $cellStyle = $this->readCellStyle($xmlReader, $xmlReader->getElement('w:tcPr', $rowNode)); } $cell = $row->addCell($cellWidth, $cellStyle); $cellNodes = $xmlReader->getElements('*', $rowNode); foreach ($cellNodes as $cellNode) { if ($cellNode->nodeName == 'w:p') { // Paragraph - $this->readWp($xmlReader, $cellNode, $cell); + $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); } } } @@ -487,7 +533,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return array|null */ - private function readWsectPr(XMLReader $xmlReader, \DOMNode $domNode) + private function readSectionStyle(XMLReader $xmlReader, \DOMNode $domNode) { $ret = null; $mapping = array( @@ -497,34 +543,44 @@ class Word2007 extends AbstractReader implements ReaderInterface ); $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $retKey = $mapping[$nodeName]; - if ($nodeName == 'w:type') { - $ret['breakType'] = $xmlReader->getAttribute($node, 'w:val'); - } elseif ($nodeName == 'w:pgSz') { - $ret['pageSizeW'] = $xmlReader->getAttribute($node, 'w:w'); - $ret['pageSizeH'] = $xmlReader->getAttribute($node, 'w:h'); - $ret['orientation'] = $xmlReader->getAttribute($node, 'w:orient'); - } elseif ($nodeName == 'w:pgMar') { - $ret['topMargin'] = $xmlReader->getAttribute($node, 'w:top'); - $ret['leftMargin'] = $xmlReader->getAttribute($node, 'w:left'); - $ret['bottomMargin'] = $xmlReader->getAttribute($node, 'w:bottom'); - $ret['rightMargin'] = $xmlReader->getAttribute($node, 'w:right'); - $ret['headerHeight'] = $xmlReader->getAttribute($node, 'w:header'); - $ret['footerHeight'] = $xmlReader->getAttribute($node, 'w:footer'); - $ret['gutter'] = $xmlReader->getAttribute($node, 'w:gutter'); - } elseif ($nodeName == 'w:cols') { - $ret['colsNum'] = $xmlReader->getAttribute($node, 'w:num'); - $ret['colsSpace'] = $xmlReader->getAttribute($node, 'w:space'); - } elseif (in_array($nodeName, array('w:headerReference', 'w:footerReference'))) { - $id = $xmlReader->getAttribute($node, 'r:id'); - $ret['headerFooter'][$id] = array( - 'method' => $retKey, - 'type' => $xmlReader->getAttribute($node, 'w:type'), - ); + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:type': + $ret['breakType'] = $xmlReader->getAttribute('w:val', $node); + break; + + case 'w:pgSz': + $ret['pageSizeW'] = $xmlReader->getAttribute('w:w', $node); + $ret['pageSizeH'] = $xmlReader->getAttribute('w:h', $node); + $ret['orientation'] = $xmlReader->getAttribute('w:orient', $node); + break; + + case 'w:pgMar': + $ret['topMargin'] = $xmlReader->getAttribute('w:top', $node); + $ret['leftMargin'] = $xmlReader->getAttribute('w:left', $node); + $ret['bottomMargin'] = $xmlReader->getAttribute('w:bottom', $node); + $ret['rightMargin'] = $xmlReader->getAttribute('w:right', $node); + $ret['headerHeight'] = $xmlReader->getAttribute('w:header', $node); + $ret['footerHeight'] = $xmlReader->getAttribute('w:footer', $node); + $ret['gutter'] = $xmlReader->getAttribute('w:gutter', $node); + break; + + case 'w:cols': + $ret['colsNum'] = $xmlReader->getAttribute('w:num', $node); + $ret['colsSpace'] = $xmlReader->getAttribute('w:space', $node); + break; + + case 'w:headerReference': + case 'w:footerReference': + $id = $xmlReader->getAttribute('r:id', $node); + $ret['hf'][$id] = array( + 'method' => $property, + 'type' => $xmlReader->getAttribute('w:type', $node), + ); + break; } } @@ -536,46 +592,61 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return string|array|null */ - private function readWpPr(XMLReader $xmlReader, \DOMNode $domNode) + private function readParagraphStyle(XMLReader $xmlReader, \DOMNode $domNode) { - $ret = null; + $style = null; if ($xmlReader->elementExists('w:pPr', $domNode)) { if ($xmlReader->elementExists('w:pPr/w:pStyle', $domNode)) { - $ret = $xmlReader->getAttribute('w:pPr/w:pStyle', 'w:val', $domNode); + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:pStyle'); } else { - $ret = array(); + $style = array(); $mapping = array( - 'w:jc' => 'align', 'w:ind' => 'indent', 'w:spacing' => 'spacing', - 'w:basedOn' => 'basedOn', 'w:next' => 'next', + 'w:ind' => 'indent', 'w:spacing' => 'spacing', + 'w:jc' => 'align', 'w:basedOn' => 'basedOn', 'w:next' => 'next', 'w:widowControl' => 'widowControl', 'w:keepNext' => 'keepNext', 'w:keepLines' => 'keepLines', 'w:pageBreakBefore' => 'pageBreakBefore', ); + $nodes = $xmlReader->getElements('w:pPr/*', $domNode); foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $retKey = $mapping[$nodeName]; - if ($nodeName == 'w:ind') { - $ret['indent'] = $xmlReader->getAttribute($node, 'w:left'); - $ret['hanging'] = $xmlReader->getAttribute($node, 'w:hanging'); - } elseif ($nodeName == 'w:spacing') { - $ret['spaceAfter'] = $xmlReader->getAttribute($node, 'w:after'); - $ret['spaceBefore'] = $xmlReader->getAttribute($node, 'w:before'); - $ret['line'] = $xmlReader->getAttribute($node, 'w:line'); - } elseif (in_array($nodeName, array('w:keepNext', 'w:keepLines', 'w:pageBreakBefore'))) { - $ret[$retKey] = true; - } elseif (in_array($nodeName, array('w:widowControl'))) { - $ret[$retKey] = false; - } elseif (in_array($nodeName, array('w:jc', 'w:basedOn', 'w:next'))) { - $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:ind': + $style['indent'] = $xmlReader->getAttribute('w:left', $node); + $style['hanging'] = $xmlReader->getAttribute('w:hanging', $node); + break; + + case 'w:spacing': + $style['spaceAfter'] = $xmlReader->getAttribute('w:after', $node); + $style['spaceBefore'] = $xmlReader->getAttribute('w:before', $node); + // Commented. Need to adjust the number when return value is null + // $style['spacing'] = $xmlReader->getAttribute('w:line', $node); + break; + + case 'w:keepNext': + case 'w:keepLines': + case 'w:pageBreakBefore': + $style[$property] = true; + break; + + case 'w:widowControl': + $style[$property] = false; + break; + + case 'w:jc': + case 'w:basedOn': + case 'w:next': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; } } } } - return $ret; + return $style; } /** @@ -583,50 +654,68 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return string|array|null */ - private function readWrPr(XMLReader $xmlReader, \DOMNode $domNode) + private function readFontStyle(XMLReader $xmlReader, \DOMNode $domNode) { - $ret = null; + $style = null; + // Hyperlink has an extra w:r child + if ($domNode->nodeName == 'w:hyperlink') { + $domNode = $xmlReader->getElement('w:r', $domNode); + } if ($xmlReader->elementExists('w:rPr', $domNode)) { if ($xmlReader->elementExists('w:rPr/w:rStyle', $domNode)) { - $ret = $xmlReader->getAttribute('w:rPr/w:rStyle', 'w:val', $domNode); + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:rPr/w:rStyle'); } else { - $ret = array(); + $style = array(); $mapping = array( 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', 'w:strike' => 'strikethrough', 'w:u' => 'underline', 'w:highlight' => 'fgColor', 'w:sz' => 'size', 'w:rFonts' => 'name', 'w:vertAlign' => 'superScript', ); + $nodes = $xmlReader->getElements('w:rPr/*', $domNode); foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $retKey = $mapping[$nodeName]; - if ($nodeName == 'w:rFonts') { - $ret['name'] = $xmlReader->getAttribute($node, 'w:ascii'); - $ret['hint'] = $xmlReader->getAttribute($node, 'w:hint'); - } elseif (in_array($nodeName, array('w:b', 'w:i', 'w:strike'))) { - $ret[$retKey] = true; - } elseif (in_array($nodeName, array('w:u', 'w:highlight', 'w:color'))) { - $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); - } elseif ($nodeName == 'w:sz') { - $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val') / 2; - } elseif ($nodeName == 'w:vertAlign') { - $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); - if ($ret[$retKey] == 'superscript') { - $ret['superScript'] = true; - } else { - $ret['superScript'] = false; - $ret['subScript'] = true; - } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:rFonts': + $style['name'] = $xmlReader->getAttribute('w:ascii', $node); + $style['hint'] = $xmlReader->getAttribute('w:hint', $node); + break; + + case 'w:b': + case 'w:i': + case 'w:strike': + $style[$property] = true; + break; + + case 'w:u': + case 'w:highlight': + case 'w:color': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; + + case 'w:sz': + $style[$property] = $xmlReader->getAttribute('w:val', $node) / 2; + break; + + case 'w:vertAlign': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + if ($style[$property] == 'superscript') { + $style['superScript'] = true; + } else { + $style['superScript'] = false; + $style['subScript'] = true; + } + break; } } } } - return $ret; + return $style; } /** * Read w:tblPr @@ -634,44 +723,49 @@ class Word2007 extends AbstractReader implements ReaderInterface * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" */ - private function readWtblPr(XMLReader $xmlReader, \DOMNode $domNode) + private function readTableStyle(XMLReader $xmlReader, \DOMNode $domNode) { - $ret = null; + $style = null; $margins = array('top', 'left', 'bottom', 'right'); $borders = $margins + array('insideH', 'insideV'); if ($xmlReader->elementExists('w:tblPr', $domNode)) { if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { - $ret = $xmlReader->getAttribute('w:tblPr/w:tblStyle', 'w:val', $domNode); + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle'); } else { - $ret = array(); + $style = array(); $mapping = array( - 'w:tblCellMar' => 'cellMargin', 'w:tblBorders' => 'border', + 'w:tblCellMar' => 'cellMargin', + 'w:tblBorders' => 'border', ); + $nodes = $xmlReader->getElements('w:tblPr/*', $domNode); foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $retKey = $mapping[$nodeName]; - if ($nodeName == 'w:tblCellMar') { - foreach ($margins as $side) { - $ucfirstSide = ucfirst($side); - $ret["cellMargin$ucfirstSide"] = $xmlReader->getAttribute("w:$side", 'w:w', $node); - } - } elseif ($nodeName == 'w:tblBorders') { - foreach ($borders as $side) { - $ucfirstSide = ucfirst($side); - $ret["border{$ucfirstSide}Size"] = $xmlReader->getAttribute("w:$side", 'w:sz', $node); - $ret["border{$ucfirstSide}Color"] = $xmlReader->getAttribute("w:$side", 'w:color', $node); - } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:tblCellMar': + foreach ($margins as $side) { + $ucfSide = ucfirst($side); + $style["cellMargin$ucfSide"] = $xmlReader->getAttribute('w:w', $node, "w:$side"); + } + break; + + case 'w:tblBorders': + foreach ($borders as $side) { + $ucfSide = ucfirst($side); + $style["border{$ucfSide}Size"] = $xmlReader->getAttribute('w:sz', $node, "w:$side"); + $style["border{$ucfSide}Color"] = $xmlReader->getAttribute('w:color', $node, "w:$side"); + } + break; } } } } - return $ret; + return $style; } /** @@ -679,9 +773,9 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return array|null */ - private function readWtcPr(XMLReader $xmlReader, \DOMNode $domNode) + private function readCellStyle(XMLReader $xmlReader, \DOMNode $domNode) { - $ret = null; + $style = null; $mapping = array( 'w:shd' => 'bgColor', 'w:vAlign' => 'valign', 'w:textDirection' => 'textDirection', @@ -689,30 +783,81 @@ class Word2007 extends AbstractReader implements ReaderInterface ); $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $retKey = $mapping[$nodeName]; - if ($nodeName == 'w:shd') { - $ret['bgColor'] = $xmlReader->getAttribute($node, 'w:fill'); - } else { - $ret[$retKey] = $xmlReader->getAttribute($node, 'w:val'); + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:shd': + $style['bgColor'] = $xmlReader->getAttribute('w:fill', $node); + break; + + default: + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; } } - return $ret; + return $style; } /** - * Return item of array + * Get relationship array * - * @param array $array - * @param integer $key - * @return string + * @param string $filename + * @param string $xmlFile + * @param string $targetPrefix + * @return array */ - private static function arrayItem($array, $key = 0) + private function getRels($filename, $xmlFile, $targetPrefix = '') { - return (isset($array[$key]) ? $array[$key] : null); + $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/'; + $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; + + $rels = array(); + + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($filename, $xmlFile); + $nodes = $xmlReader->getElements('*'); + foreach ($nodes as $node) { + $rId = $xmlReader->getAttribute('Id', $node); + $type = $xmlReader->getAttribute('Type', $node); + $target = $xmlReader->getAttribute('Target', $node); + + // Remove URL prefixes from $type to make it easier to read + $type = str_replace($metaPrefix, '', $type); + $type = str_replace($officePrefix, '', $type); + $docPart = str_replace('.xml', '', $target); + + // Do not add prefix to link source + if (!in_array($type, array('hyperlink'))) { + $target = $targetPrefix . $target; + } + + // Push to return array + $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart); + } + ksort($rels); + + return $rels; + } + + /** + * Returns the target of image, object, or link as stored in ::readMainRels + * + * @param string $docPart + * @param string $rId + * @return string|null + */ + private function getMediaTarget($docPart, $rId) + { + $target = null; + if (array_key_exists($docPart, $this->rels)) { + if (array_key_exists($rId, $this->rels[$docPart])) { + $target = $this->rels[$docPart][$rId]['target']; + } + } + + return $target; } } diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 15ed9da3..0f6ce3f0 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -38,7 +38,7 @@ class XMLReader * * @param string $zipFile * @param string $xmlFile - * @return \DOMDocument + * @return \DOMDocument|false */ public function getDomFromZip($zipFile, $xmlFile) { @@ -54,6 +54,7 @@ class XMLReader } $contents = $zip->getFromName($xmlFile); $zip->close(); + if ($contents === false) { return false; } else { @@ -69,7 +70,7 @@ class XMLReader * @param string $path * @return \DOMNodeList */ - public function getElements($path, \DOMNode $context = null) + public function getElements($path, \DOMNode $contextNode = null) { if ($this->dom === null) { return array(); @@ -78,42 +79,42 @@ class XMLReader $this->xpath = new \DOMXpath($this->dom); } - return $this->xpath->query($path, $context); + return $this->xpath->query($path, $contextNode); } /** - * Get elements + * Get element * * @param string $path - * @return \DOMNodeList + * @return \DOMNode|null */ - public function getElement($path, \DOMNode $context = null) + public function getElement($path, \DOMNode $contextNode) { - $elements = $this->getElements($path, $context); + $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { return $elements->item(0); } else { - return false; + return null; } } /** * Get element attribute * - * @param string|\DOMNode $path * @param string $attribute - * @return null|string + * @param string $path + * @return string|null */ - public function getAttribute($path, $attribute, \DOMNode $context = null) + public function getAttribute($attribute, \DOMElement $contextNode, $path = null) { - if ($path instanceof \DOMNode) { - $return = $path->getAttribute($attribute); + if (is_null($path)) { + $return = $contextNode->getAttribute($attribute); } else { - $elements = $this->getElements($path, $context); + $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { $return = $elements->item(0)->getAttribute($attribute); } else { - $return = ''; + $return = null; } } @@ -124,29 +125,28 @@ class XMLReader * Get element value * * @param string $path - * @return null|string + * @return string|null */ - public function getValue($path, \DOMNode $context = null) + public function getValue($path, \DOMNode $contextNode) { - $elements = $this->getElements($path, $context); + $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { - $return = $elements->item(0)->nodeValue; + return $elements->item(0)->nodeValue; } else { - $return = ''; + return null; } - - return ($return == '') ? null : $return; } /** * Count elements * * @param string $path - * @return \DOMNodeList + * @return integer */ - public function countElements($path, \DOMNode $context = null) + public function countElements($path, \DOMNode $contextNode) { - $elements = $this->getElements($path, $context); + $elements = $this->getElements($path, $contextNode); + return $elements->length; } @@ -156,8 +156,8 @@ class XMLReader * @param string $path * @return \DOMNodeList */ - public function elementExists($path, \DOMNode $context = null) + public function elementExists($path, \DOMNode $contextNode) { - return $this->getElements($path, $context)->length > 0; + return $this->getElements($path, $contextNode)->length > 0; } } diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 46d5c036..60b7198c 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -31,6 +31,13 @@ class ZipArchive const OVERWRITE = 'OVERWRITE'; const CREATE = 'CREATE'; + /** + * Number of files (emulate ZipArchive::$numFiles) + * + * @var string + */ + public $numFiles = 0; + /** * Temporary storage directory * @@ -48,13 +55,14 @@ class ZipArchive /** * Open a new zip archive * - * @param string $fileName Filename for the zip archive + * @param string $filename Filename for the zip archive * @return boolean */ - public function open($fileName) + public function open($filename) { $this->tempDir = sys_get_temp_dir(); - $this->zip = new \PclZip($fileName); + $this->zip = new \PclZip($filename); + $this->numFiles = count($this->zip->listContent()); return true; } @@ -138,19 +146,19 @@ class ZipArchive } /** - * Find if given fileName exist in archive (Emulate ZipArchive locateName()) + * Find if given file name exist in archive (Emulate ZipArchive locateName()) * - * @param string $fileName Filename for the file in zip archive + * @param string $filename Filename for the file in zip archive * @return boolean */ - public function locateName($fileName) + public function locateName($filename) { $list = $this->zip->listContent(); $listCount = count($list); $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($fileName) || - strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + if (strtolower($list[$i]["filename"]) == strtolower($filename) || + strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { $listIndex = $i; break; } @@ -160,12 +168,12 @@ class ZipArchive } /** - * Extract file from archive by given fileName (Emulate ZipArchive getFromName()) + * Extract file from archive by given file name (Emulate ZipArchive getFromName()) * - * @param string $fileName Filename for the file in zip archive + * @param string $filename Filename for the file in zip archive * @return string $contents File string contents */ - public function getFromName($fileName) + public function getFromName($filename) { $list = $this->zip->listContent(); $listCount = count($list); @@ -173,8 +181,8 @@ class ZipArchive $contents = null; for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($fileName) || - strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + if (strtolower($list[$i]["filename"]) == strtolower($filename) || + strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { $listIndex = $i; break; } @@ -183,11 +191,11 @@ class ZipArchive if ($listIndex != -1) { $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); } else { - $fileName = substr($fileName, 1); + $filename = substr($filename, 1); $listIndex = -1; for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($fileName) || - strtolower($list[$i]["stored_filename"]) == strtolower($fileName)) { + if (strtolower($list[$i]["filename"]) == strtolower($filename) || + strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { $listIndex = $i; break; } @@ -200,4 +208,21 @@ class ZipArchive return $contents; } + + /** + * Returns the name of an entry using its index + * + * @param integer $index + * @return string|false + */ + public function getNameIndex($index) + { + $list = $this->zip->listContent(); + $listCount = count($list); + if ($index <= $listCount) { + return $list[$index]['filename']; + } else { + return false; + } + } } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index ab1159ce..3c2eef09 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; /** - * Style + * Style collection */ class Style { @@ -91,7 +91,7 @@ class Style /** * Reset styles */ - public static function reset() + public static function resetStyles() { self::$styles = array(); } @@ -109,7 +109,7 @@ class Style /** * Get all styles * - * @return \PhpOffice\PhpWord\Style\Font[] + * @return Font[] */ public static function getStyles() { diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index cb3ad02f..d84bf770 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -152,9 +152,9 @@ class TOC } /** - * Reset footnotes + * Reset titles */ - public static function reset() + public static function resetTitles() { self::$titles = array(); } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 5a489542..c89f09ba 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -13,6 +13,7 @@ use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\DocProps; @@ -97,11 +98,11 @@ class Word2007 extends AbstractWriter implements WriterInterface // Add header/footer contents $overrides = array(); - $rID = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements + $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements $sections = $this->phpWord->getSections(); foreach ($sections as $section) { - $this->addHeaderFooterContent($section, $objZip, 'header', $rID); - $this->addHeaderFooterContent($section, $objZip, 'footer', $rID); + $this->addHeaderFooterContent($section, $objZip, 'header', $rId); + $this->addHeaderFooterContent($section, $objZip, 'footer', $rId); } // Add footnotes media files, relations, and contents @@ -113,7 +114,7 @@ class Word2007 extends AbstractWriter implements WriterInterface } $objZip->addFromString('word/footnotes.xml', $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())); $this->cTypes['override']["/word/footnotes.xml"] = 'footnotes'; - $this->docRels[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rID); + $this->docRels[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rId); } // Write dynamic files @@ -207,12 +208,11 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Add header/footer content * - * @param \PhpOffice\PhpWord\Element\Section $section * @param mixed $objZip * @param string $elmType - * @param integer $rID + * @param integer $rId */ - private function addHeaderFooterContent(&$section, $objZip, $elmType, &$rID) + private function addHeaderFooterContent(Section &$section, $objZip, $elmType, &$rId) { $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; $writeFunction = $elmType == 'header' ? 'writeHeader' : 'writeFooter'; @@ -220,11 +220,11 @@ class Word2007 extends AbstractWriter implements WriterInterface $elmObjects = $section->$getFunction(); foreach ($elmObjects as $index => &$elmObject) { $elmCount++; - $elmObject->setRelationId(++$rID); + $elmObject->setRelationId(++$rId); $elmFile = "{$elmType}{$elmCount}.xml"; $objZip->addFromString("word/$elmFile", $this->getWriterPart($elmType)->$writeFunction($elmObject)); $this->cTypes['override']["/word/$elmFile"] = $elmType; - $this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rID); + $this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId); } } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index a5f9a5e0..12291694 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -93,7 +93,7 @@ class Base extends AbstractWriterPart */ protected function writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) { - $rID = $link->getRelationId() + ($link->isInSection() ? 6 : 0); + $rId = $link->getRelationId() + ($link->isInSection() ? 6 : 0); $linkName = $link->getLinkName(); if (is_null($linkName)) { $linkName = $link->getLinkSrc(); @@ -106,7 +106,7 @@ class Base extends AbstractWriterPart $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); } $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rID); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); $xmlWriter->writeAttribute('w:history', '1'); $xmlWriter->startElement('w:r'); $this->writeInlineFontStyle($xmlWriter, $styleFont); diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index 47aea9a3..25fd8ae8 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -32,7 +32,7 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, count(Footnote::getFootnoteElements())); $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); - Footnote::reset(); + Footnote::resetElements(); $this->assertEquals(0, count(Footnote::getFootnoteElements())); } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 93dfaf87..0b98bfd2 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -95,7 +95,7 @@ class MediaTest extends \PHPUnit_Framework_TestCase $this->assertEquals(2, Media::countElements('footer1')); - Media::reset(); + Media::resetElements(); $this->assertEquals(0, Media::countElements('footer1')); } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index b323ece4..bf28fa88 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -44,7 +44,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase } $this->assertNull(Style::getStyle('Unknown')); - Style::reset(); + Style::resetStyles(); $this->assertEquals(0, count(Style::getStyles())); } diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 2b9d50e7..7092795a 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -80,7 +80,7 @@ class TOCTest extends \PHPUnit_Framework_TestCase $i++; } - TOC::reset(); + TOC::resetTitles(); $this->assertEquals(0, count($toc->getTitles())); } From db129b4805b580e173be0e39144b41c8275927c7 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 9 Apr 2014 18:47:10 +0700 Subject: [PATCH 075/146] Update footnote unit tests --- src/PhpWord/Footnote.php | 5 ++++- tests/PhpWord/Tests/FootnoteTest.php | 17 +++++++++-------- .../Tests/_files/documents/reader.docx | Bin 14208 -> 69796 bytes 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Footnote.php b/src/PhpWord/Footnote.php index 2e38a962..2e267c2a 100644 --- a/src/PhpWord/Footnote.php +++ b/src/PhpWord/Footnote.php @@ -48,12 +48,15 @@ class Footnote */ public static function setElement($index, FootnoteElement $footnote) { - self::$elements[$index] = $footnote; + if (array_key_exists($index, self::$elements)) { + self::$elements[$index] = $footnote; + } } /** * Get element by index * + * @param integer $index * @return FootnoteElement * @since 0.9.2 */ diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php index 25fd8ae8..6dcda73f 100644 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ b/tests/PhpWord/Tests/FootnoteTest.php @@ -23,16 +23,17 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase */ public function testFootnote() { - $footnoteElement = new \PhpOffice\PhpWord\Element\Footnote(); - $rIdFootnote = Footnote::addFootnoteElement($footnoteElement); - $rIdLink = Footnote::addFootnoteLinkElement('http://test.com'); + $footnote1 = new \PhpOffice\PhpWord\Element\Footnote('default'); + $footnote2 = new \PhpOffice\PhpWord\Element\Footnote('first'); + $rId = Footnote::addElement($footnote1); + Footnote::setElement(1, $footnote2); - $this->assertEquals(1, $rIdFootnote); - $this->assertEquals(1, $rIdLink); - $this->assertEquals(1, count(Footnote::getFootnoteElements())); - $this->assertEquals(1, count(Footnote::getFootnoteLinkElements())); + $this->assertEquals(1, $rId); + $this->assertEquals(1, count(Footnote::getElements())); + $this->assertEquals($footnote2, Footnote::getElement(1)); + $this->assertNull(Footnote::getElement(2)); Footnote::resetElements(); - $this->assertEquals(0, count(Footnote::getFootnoteElements())); + $this->assertEquals(0, Footnote::countElements()); } } diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx b/tests/PhpWord/Tests/_files/documents/reader.docx index e2ceeb646e699713e15fb13b7f0da74be49688ee..2143c628c5132f5948c339538bef2c2fabdab545 100644 GIT binary patch literal 69796 zcmeFXWl&w;w=H;ZhoHgr-~@MfcXxMpm!JWHI|qUu+}#Q8?!jGyJ0Z~g?tSm|?Y{r+ zer+GRUazXTKkU6~SB<^L9MhJv927Jb02Tlb0077Ub6D03GY|j(4k7@634n*x6LWHO zw{UbfQulGTa5G@^cCaTcfQF>W13-T4|Nqzjz+Ye>O(A}s`BTKD^y{|~t(4XdxG?2; zfh(7=R2mGe<(x*?pwXO*=JyiWFJg=iz0N=mqYEf-$O7Y{eJJjxTh2agrF1IVcIn)c zHO!ou{w?V~Qypv|Usl(_93S*IN=vlnjG!<{dlZ~p&pR)v8@3)0Hc5LpPle^GWoUB` z9EWk1$Y}LMs)+)0a!#Z;yrf*P`VpF7MiOx=>2Dy2+MDcLq81fL#&cqVl zVT&!JG;ho#FgBf1M=sIx$5m2fJ!Mh2aZ`ox1fLLh54QH%LZ+T7-7cu_G^;`WCbl+=m$PWWZ3lTDWgg%X zlu!eQxUgmErFJXZ??sy3($YTY^ugixcPN1J|3V1d!-|DbKZL*q3IIU*5CS7t3wt*v z#(%E=zX1FX?DhWvdgc76Z9nrT*loZ3OH%jv129sN_*4;=EB#==*E05Ii7FVIbt)$# z^me>;c4ZO{(DO4e|K8Hd?;)B6?-FQ)LuqxKvOLt3B((VWonQ(hcz(w3Thb-VwSq@r zbKn3m4O-Du*nn%aT#}dgj%Fm7w=n^cWai+Ok!Aq~DHS3$q}$b(@a^Zf@TB7Jz1My*UZ25@9t&lklQOT?rSliM<2s}5mQxK^y- zigWY)&#|quw)n^A1-flw`uJ*KzsD78@5MRIWyR|r$KTYgwSm+MBg8k~uJym=n1RQ6 zWLhcQ@$X%*!memB3gcC~J{;sfyH70}Nn_TB`$T<&RYCwfgqM@6In%%UkhznYhr>rm z{U?_GSAT-|2&f;s|Hod9Y2%6?e3E#Seihpna8cWgOhF;lCjErfyA(?uMb=E=hj@31 zhtGk+^gaBSh2ySY{E!*_Ftt;=jA4(Dg~C+5`v3-Wc{5pZ%_0JsEJ8Eko`CLUFx}>SqyHzwf5-|S!_~$NM zcgD#|Iip1rnH?!9LI#ajpPls5%D<}VO>p48l7%eq@8etKjH(N#oH8j?O zw)EHanW_YHh%1vTYHBKh2@PD(R^t6n(*wUe<;{!A4D9q#RHGCp=1OqNw`dAPz4h4} zuLUHuO7?H{UIQn*ndh_#AuCfpiE_q`D(jB9*@aXSe*+X8X0_!67n-$69v2yZHWkHk zi`NuV)kRAzwo9dl{t<5dVCpoQ-uCfOuHXR-OZF{vcCoj2B{uUNv4Kw*%z}GoLJG@= zo(gSqzFn@H_5(LN%Kq;Ch#kHb^S=DG`7=FbnDf&+Cf;UfsQ^t?Z&?OMsL62=Hq84S z6pIhszalq@+eVSlM}qkH1pq+*;OxJV`#;ip9e=}hb?mvDE#Mo`een;O7-(E(6hZ>C z;mpyK>y?YqJGusGq*c;J-U{pt{U6K6NO!$c$#;J|DajCmdll!vdw7L^|GWih`QFa& zk(0_%nKAYSA7roKnB>#*6Hmb|36WGAJu+a>dicv_ZrZevS?6OYqJlyj~Og!Bb;!6n$6Biq!H5xS++aC zJ4r*Dh>mqA3gQf5gJlUw<;FBtu`sE(Kwp#@it?v0IQ=S!=8e&w$l%nG+T0NDADCfM zFA;fn)O=)Uy>@XiY6#XbD5H>hB4KsYg(w8m;jrHWVa?m(qYlVN9;(Po{<0FqP#W}3 z!)}x9`yI}ZGpAgBJ6?gah8EeUMkULSVJkEj@o5!#WthbZJIf}9%hQ4RG-+6z-J%Md zg~boTYxLUT{}!GT09~m*DzUVij_!6j56|zs^RP83N_GMSL=I*U+2 z4v1UC?Y7zXqY|B9nOmo)!?r&l?h$PzGXVS`*@{N@IP$h^c%-|#`Qa-frrN)jrFR42 zEp;VJkqEnpV`g!KW@R4=fBlIVQ&$xBoi(GS-c=LsHjq%|^HVhNd!|0CopgaXYX}(5 zpS(;T(^-%_wiaGOlTz!cb5K`tn*L_|X(x5l|IzucX>>8av5P=)vOy2Jd&lC1fx#ur z-|f(ePl98L&oP968u=iID0V8KoTcZ%ux_wP5 zr2PEO0x>b(qEKZ7_d$0gJjoWDVWmk&amd@D;bq_E9DhMo(C7{MQ^LwaM%oy$s2XFBP?OCZD1Wu z9m?XBNxGxIeSZ+6F8gd^hxghCO2`Nbj$$O<0VpT>k)e;D#!UruU6d*r$+Tq9_gPke z3Rv_@%?S~WkZ_t6h2ufI8ptEI&G+zorrlwo9nc-PAR3cxe^<61%>4QlkZSX^fE*9@ zWWV`*ti^$ihTc*>4*zS)K(x{`>M%d2zeBJWC~-`lxFS$siJXGI+J84Y8v_ed9j5H7 zTZG~qzW#05pXdd-S}-640qq(XQ3bsw1qtnIkEli*)r1nttci@%I|_XbO*m6EO6JMs z$=g-2x?0{?-#=h_SiV-TEIWK*(zP2Pc&8$dBOoL443D>x*UUM1p2-3(15EQBe@zBm zF=DAP?#%_B|LkC~KX)qjIQad>X0Iy(aGtt)KvC{UU*-t_l4~t)*13jA%E%C;vndsH%m@D(95)pzFa6n+#MBH;T()V|ZPqfc7b z7^HGjEcrll`j9X;bda#+9l%x^Q|RjS z8D^2}V~AGF&}G3njXk-!K6yY;gzNoLGm|#+huqp0ap!k+nlvzCseIu{AP;s_+MMg_P7(hVG%UPt-*i@-7Zx{M6Slh?eJgBz4yWB*Vn0^Vq8(~-y{98Xb)34WQze7ih%Qe5_YdEkb_e*bo8avCWc_3G84cUNoaco$V1F84jcs+ z$)&J+*m1vvRKmlbr61*RG|jjvo%Nlzee;1wG~r_6dpo<0D|{K-&4s=U&#;>L{SaRE zR*Tn)sqM6@yv)eG%3yeUQ&^j$kkMkbYY9!pMe^5HGLr;H0fyegKfCv`$Z-ZjX>jWDw|n3NX~E`ub_>&MF#h zv!JkKbwp#7y8_y2e0(36HdLd{mS<>wx5@Vj?nbQvF{RjB{M2V%rW&g>)Pp0ONoMu^ zZI)kx3L<8gHO0~b%WZo|#QK*X3XaOozSCIDpYdDx^Kn1rCK)g%kAph>0dnoPe-w4_ zFD+@C6fnB7EvuI&_)N)}gwHd=E^syA$sZVXR#2nUc z4HFKH*179-S;m2|4@S|FS-Mk*gY!-vN)-2AMh&*Gt22$`KI*f5i$O>-OI)X4p_7DP zWa$ST2$lUNcHT0&_t$)^9>ujcx|M_gfp4OgZXQ=qhV_>nx?H&moSa7XXzxh>D%&)T z_gLZn=r%fhlv1DmYqn|WCspBpRI$M{FxgpJl8mybZEhZYaf*ECK!Xe-c^r$fTd2?`t3(`Ec!t(yc)6J zlMm0u9g8aHD#1KN4b7>v&+BcODYP$^oiy}t?2GyKj=0^4ZWi+!1V? z7Focar%6WI=-X_j<%JS;pp`N{6_BU3^Y%oEJuOk&3PwUTvj zL_9)%S>;*RY|GysNT+|Bh$u{ zRqII;s$C^olt|VP@Zq)?s#n#L!N4`cC@n}(`#mi!uM#x_*Ghv#f&p3DrRNA1skXK^ z92HAUp+}K>@fC-jyr8BCo5^*u<^?H9?rq(k{H;%NNIV*)r$hLpu*JRNR6c+C_Y|dK zNn`_;(UMfW5oW<{^)f*H7GVHgDCOHF$VK*1I!OG^1UCK8Gj|Rq|GVtPiH~kXODjXy zcHLO0t5b+GBLXgF_p_&V?7UWQ7SfQ8V=Rb^w^8oQUe8EMIr!H8mS$ zIY)>YbZV`L%JuAtw|!{zbWX19A9i%If4tu?FYiVbn2FS=!`gbH5oS(_?9WvxsO* zVwZrkoxMLjOSec>&XhSQMFEgGsM;hIbh+^&h{-*u8}nhu;96*06pKeGAMjAHSEh{i z>0n9S%M(bHHaTx9G054ge8+UMkyS$&(#H!XVwhyaTH(j`g>;W4@-xqFgQ_ibB9bgB zWoETOPc}?Ilff4`pOMH=n{p6cipC0&)yl=i9}@{p@|?a)7_zc4UiV74=>p33^8J(@ z{(N+A?BER358#&wT!Kc}qzTH!m7;bZpm>Q?19tK^sF5=#_xI+~O{%!;jmJY+)2k8I9An;DGNw?oAo-7K^%Zsxx|C+c_GhIR$I5e}!{5BGu=o zhDABqOJLt%Z3vcMnss|uOBMpNf5LgdSd}LQtY$mWpG#R`+-fLldNDFurA1<@I+Ov zV!}Bx__HNl7W{3X@EUNqIt$AS(%iXyq@gCU7;%h&9^C9_%Br`jrwDT#9JcDtq?dPYp@gw6>m*E&5T> z(Z00m4yS+c%fvdihR8YQwNoLfK;uo2B~J2#UlB1Z7;l>mTI94^9kD{{psw8^trCc0 zCkWqw4}Rg%+{X<~7YdZ72Oq>gAXHY5{#p9%W2#9|ehodw;G<2?e5aE~Zm;uI1MPJh zH1SxSou|02X%=Py!awc#l)dXCOXY%D>JsUt+bxd}-PL92|9n9KDubc7rd{6|E6j}! z)c@Pr?LZbk^s}-Uk8Xfemph_GY#$T)kt53xHPqsSa()g1;i$n`+6k{~%5$_4VzS}U zeZdHJ%teE9dF-@m`8c=HSN+C%ZF4yh$5S=_iI+WJ%aNYHqJW(8k?2oUS38BR!eaot z)hMFn)n$T5lz}tT=X5xujsEA`nG|#+FiOLOddx&9Jap~W)AJ%^a44i84PxcdWNqsJ)-JP8RIl1IcqwF#H%~yp( zwxMH#+c-oc=wv1MaBEulEBkywV_UCr?jujlbT4zaA0{C-7P1;^UvFwWdTNwx=DPUP zqb+Ca;D|Q4T3;#{eN!d$a<|54$Ra~WSn-R3_9?Kht%>)JKY3sMlN+Tra>pLy<+S`iP8 z`a9A0ty z;|UeK<%V{I9r3Y}7RQ3BC#-$lLijH&g=CH;RO}Rbj%b>;gOH~?gBRQ$`7k@^IkXnE z#!SS12I2vA<{R=4YIsT{u8^f2dgqM|&BX+dwnT7jHVl==Syf{g_zD=G%Y*R|VFp=r z*QZP1^M$r%=G}R6r*hJj9_iItcn^F|P!^#hi!KQXagGj`tyy1n(g7e8*(N|yeOF#) zgNw2N5w$@6Q#=XX{HCnN!prF!%C*tIq|Q!t*>lZDN@Mh&Q<{ILPRh7r#YgOWOr7G> z-lUG$43}-^R$=NWPlt1kg~)v=t_waq=M$EmQ!A6rLW#J3-Fkg6HZu50prDH&!jm=c zo})}&EEfk zW&`^XFILRaRVVz&R>Do6hqZ5(oZyV`mEpwKMN5W!DC3h&Q)HK19h}~;iF>2w)S_?{r(1MV0RaR$5qjN@P3CNE>SknA4 z)uYFVgSRgYecfa3eaSsIJ(k)aB3=DDV;n5Wz09e|TFC$z`q14@)bif$e;6=* zG~NGgkpa}d1oh)2e;m~K$3E`;TMypB!raD$$;QFN%7TT_*4e`9edT={@JUuuMiKz= z!32nZhD`5o06sBQ2@!QARbEmn^DqDGBlToqWG1EYaIiSP*t zNr8;iq~r_~goHF)v<%EF?Ck6$)I0**to)2@?5zL11Ofp80T~Gy7X<~Em5h*#_5bvG z?*X90L)<~!K|zoMAkiV9&>`Lj03;tEVIcl({g+P#fPjR8hJl5HM?ggS*wFL|00{vF z1qlrW0|O2Hu{+@7IRF|R27`=61Qt`p1diMVi#0egAD%+At`}Q%_6o>m>KcN8i1Qg2 z51*2XnueB+or9B$n}=6STtZSxT1Hk)T|-k#TSwQ-+``hz+Q!z+-NVz%+s8LFEIi^{ zWK?uga!P7idPXLwpb%VCTvA$AUfHA6yUssDFp`as78>|0`VRAGjc)p`oDR{=o$S>GcnAbZ8hd z7FY}s6*vcr4Mx{JLHQ3O3a%Y*W`+L>wUd4(0Vf(EbhCe;=@r|4YdJ8?gTw z*D3%R3gYAEL7@YL0MBpHG5kTwbjw;8kfJ1z;DwDD!=zXOVH8%s&kR&jN?2F12wH(D!-w*g&gq2mHI zsH(+^#dH@Z@u`XGMTb=qM|Y6JpxyH4H10VG+sX9(Sg!#VpQo&Am3=xwyAbh|-(%0@da6dI3b9=ewtboqUqVN%0pfSE?OHa8NtF^GSMn_(3i(`y8^6*xi_(?`Wez z^>;8~=O)RwH}AcZLFKIe+3j;=`kGuwhZR$$vOzI&Zsf6ym+Xa@9m^R5w-B@i4FvZx zwI{c`>IbRV2z+vaY608uF{u_RiueQ7IlMlBhWuV=65q(7{w9xeWYsHJv_jDKx% z78uW5jZ$Y3x154TaNW@X*-tSI;`OpS!BkWRFVcdPG9n2|>AwGGda74^h*ULX* z4cHY3_eBlezNCUqka|!KI;ad~t$iTEX+CV5>l7F$aWDBZ>{jfezgeJ54u0~vm0@6(0uUj zEHR7W9%p_%kySm#cV{P2iWX^VjuX7_eo;p&UafS$xf>+z1Ql}5j zblPLnl9(Mk88{GdWR5&2zM>2FfJ6H|ACPgyYl0sScsQ2C$#XcYrIRTrpkmZ(Oe^!+ zj!xuO<%|!c&`LL^k)Xfk1I?_bN#u!}IAT^)%5uq?-vRT&u=K7sb3jVtaQ}(F+l4$Y zGYPolu{^i%&sos7n_&4B)YMuIR5Riz4-p6_Jiovg<+HwaVE{w?mt0aYb4{arF0xkcz;CW2Sq?)!Aj3~ zc@E9KaV&}nrsu6))`o4Y-?9Ca|6^HSU0rY!<5ElAHcaXZv390WNOfGPEIAe$GFFx0>xF?DlE`+IAmUfzz2{*7fKBZ}e}vw3TXM8bhr-Vt$XvRAq3wgMrt znM+Ix-muG*o#qRI?ytDnL-gTlTiQDtM)xd>gvcM-b$C!UZaV9Zhw3d4j}q7puZg(a zrf$ibd0A@p%>){_vci9N`|h@ z@dN6UChpDk0^nHK+oXYmtWz6(b6tCf;{11jG+o`-DiSynwWr00#W2_NL?zNsyoYVc zWxBs6@PFfFkZBrcJMIx(D=k_!EjAWK%m$~4^*fM8YY|Nq&)py`d8p$V8Q#_RgeV#^uiLs*?yp`AnIMgooKf4*ln0W#si8h%*P>xHyL{Ad^4G z$-s(=yP^rE*7!Pp0jabS?Z4*a6t{gp7yrc_4OG=*=-D?rIal1Cl2firnlt4#chvZH zjaJ0Eq)-$oZ-1ss#Z$wCWuLg_!r0G^S9PWUL7|zr#FbpCariyaEE5LA$u#v2n9+O~ zb#PCOb!laE7T^OFxmaH*kh*%Iy23$$j^`#XD#>pl8_p>NAV$s<4=5trJBaPr83(n| z4&;aqM|@!FUa6}z7Jir1wp)W$;m=pgtENYrdiPrMwAf=;rB?_^#8ethm7RSq=)erX zWYgrFPEa~);dafo@2qRI+iH6=1g>C{tTwKdGl}j}W=kn`wy$S-wN5&WQXTu(F}{S` zk>Xlp@1xbq$1HPIi`U1$DMC@5F&?Uvg8qN7AvK#642JujE6a!Gta9-7z^|eLj zNEVG^u0CaLBc(vjX6H}EFylU5>Ntk4X0{>X{DcWOyL6cU9gwZTH;tn|;bZk z-avDATmeIj&|-^kt6GWB?H=reV}vZ_%trdB+lcVbUg<*_zV+(jd3E?)uuwXFHkRdS zcc*I*U5$0~QVaRVIKq*H8R)XbbEe_InAaA)dvT*`(W5;5C~}AU=AkLKn}8r*Ms9VW zzE4BM{ni-a?zOtELf%yRo&U(2KY&HQYxsMOL+<$ZaUqtm-?-E(>TK)7wd?CF)FI{3 z&Pq#d_m*u7$eYR?n&0Iqa$DB2Q$*H0ol%S=Xr}wP@;An^Dsq6G`t^yNvcm zn`IZ~k^F{q?o~9E`=e;dMZ6TYgbD5ad!S`SK;-+VW<*HN`K;if|tQAaP{cO`<3Iv=6V_ zQdxT&YKy~?8zIJm*(JV6n}%Ez3AGIx6teq56G!x5l`l{hoLhR5utla*2vI9+rVm?` z|2Nu_;4zQ?T-C+Eu%b-rPS!Iw&)z7-E# zV)UFI?k{HzVtI4yWNNsY0~I-<5leakX6Tqa!6s-1RTnbNDYg)ssxZ#ebzra$a)9?o zXwy)tZR~lw#ofcMI7EstU70?+FMrb`u5S%Iu=uWK#U0C1l}PD#9@Tho;d%K;8L6MTDa3-?IU#dG_V5 z440cnj^kCT?B)YV(&wPaxZJe`JMYbmd_aLi^&C4&(@4 zTitrFQx==d*Fo}0ofhA%fXg}-B~=lrM;o+uQE?OiD=U(z2KVo{7ll5$=C`sxN_&!6 zrbXm@e9esOU6k+;3j#3+!KTriE@b&C*NZJ^319~0DdGNUQKJnrQ|IpA5>r){sU zC`|kg*w=I${W1fol!2K>oix1gviO}VmV!lE@hZ?_gs8RDev_q*ppdn-7kKd9fiH-+ z^s^}j#TwZjb$0HF?sVl^QHS0ryK&jj63?In5PG0U(Twmw3qbP04f!7}_%gr8SmnBL zw}JJ>*{H)!QUnr&ndX+pa8M_jD8<^f`d^u)&+ox<$V z+ZYYcFf+oVrCjDV^d$8P7e&clzHh{--fIyfP$26@9-{cJ&!1^l#@Pyzo80EHO?LgF zqV=Fcdyu9VK-vr-9afo<{i7l$o3tAppJ@y;`hJKr^$ZaGaT!WJy%&)yi&aaIL_jrS%~kGOmyMovEITtJe~ZStjyhDXuT4@S_GX?g z(FB4%Ap87?=djIhJgbZmECY_E5YSFr3H)24YXHi}0kx=5orc zY6*p-q$JTu*`X}JqWPe6>ZM}o5+0&qGG}RZ*F_-HxBVK|M@LSqWVf`ivzimDT z+^JdJ6~psX#*W^m9p2pb*iA~{#)ZEDn=@20dmkk#h{}*2kyP2Q>i|b7hAKHZ<&roP z&w}ThEZ0{XF;YB^$`f4S@3Fn82AmQ2&+{OXb4x2Q=q~%r6HnIO0afxbua$W_b-{{g zjZ8{x3%81Ubq3v+twaHIjY(gbH=ap$G%ZyJYAsOKQR%=}0UK@WzSq%^gEskE&x_7} z@v?>F4uXr0I;+%(AF+J8N-HyU7%)TL7)j{2z)*!Z4eeE?ea=G|?c9(2GT-&Jdc|Vc z=|KG`EY5bntfe@p4+NKyak*OdD>!{Fx{hB$`+r&9GJZAtjwmmAgKWMQ-jDv*W* z9&j1#ZPb5S_nhQkTIkmHn;xxim0+5Vk4h&Jk$#5BkdM#2@#`T6kJa#&?Y(n`XV*~& zb9PNW%mdgmMput&C4I(qYnv7%FMBJ)xE`4vybc1-my7lyu#Wb(7B^IWF>P#=0eeU$ z<5`~PgcOCUHnnBH{aqg4PuoV{?0h*NQy8?4mR_^_$&##0k9RW7E0ilAkUw{74cpD2gSv&lk5t@WHhSpMLBcTRvJG>{?N((pO zy`krcaz0SnTy+^P(w)yaQ|bsw6DfWIEpaGWi_T@T(ylZ=(lW^bl!H zF1Td9vNmRaV2ku6C-Y@#QmxF3=oe>zVmV%3!x~olC&$>@U8*mwR%P6STq>O{oeR`y z%idp`m1RcD(QT@T!n{~zY}LkDYklApnYoYnmrN4(lF?hnbN)(rC+pW+Z!&C|l7H=x zE`{80_C*|SS#Z$xik?DXETNNQfr*5wri-ZXp<9C=$UymVv^=9Jne5L#X}WY5L600f zLL^=NDnR+W?cCEum9g?8!Sq7+<`o0#h7XL1nXEE=g3FusJuRr)Le-)Gp!y-s*XJy& z*G8YtNMpFP(pRG`V;5rQA*JhYyTWnTP&L^s1YRG{6(QP*rFKR0X&2&}0dL@U)n@A6 zLX)2~ko3e#WoU0@GqlfHlAz3f8s_S5Ejt3gkDw0|@U{W>TmUgv&(R8W8!&k=;sR?F zcpS;TSbMZ`Bh%`ZEwFpmG^{;t^7IY?sHBPJh=Rs&6ZD2>pN1ndaa&qA!rgVU$eM{K z3PCA0mSPVaNR4p%X6GH)clD{oUj^=z0`n4w@3?zrCp_>1*(1D~m+h-yoy zs%%RWPv%*6M7O{4a1rnx`>%AYpFH+K*=8oUpAUaa zNMPAt$Y#fNMswm37E*YL`l+)5Fb{dmUeq5^LdQ}0G;|JCKsI&kF@`Z38 z*4W_tf46Fl5mH4nOr3~e<(`tE2HsbYc7u+ww_|ftKVNRv*;=Gt~nxd?9UV%N7tyJ{&*c{+G_KBuPf}*(z5g zI%#ZToIBQ1I|}a5q?PvkA|KrC57*inS12pymDHv+Np`{s$O#zu!>z) zEVd(yAiiZszg!I1AO&sLu7gWgQ^rwNW~5Lm%|%#lWg9(;fz=@iIKU-tt#Lw8R6o&G zQj49G^|kj?`u4kto^L7bq|n?0>cH*B*d6MoI{HGy&C12P`uh2MWBWbe@y$aN9+_7G zd~3OGWp6xtabmwV4HO`2L^kKSjcDM!H8$1g!--kBqP)t1eHV znbe#^N&8OQZ!QvVjC?P5m0iM>%HYVsgd4HARGCMz`oax*+L$&5Z8IX4`_~f&LNTUH z&#{E$H08VwH2Ve5ao`jimTY(}kSR`S&tNKk$4_QE?$9z$bu7>aPVMOd8?4qA^JB`D z$Y8JKW{1LVjI*a=QA)q1W=6C5SI!(qD;FwWFfwqsL;;NX4p^>8=Ummyb*>#gNH_GX zrFP;T2sP8OWBw$GhNEA~oA0(Mc=jlk)mf~=jn9YX z+&6esmR~3_B@V+yPx1!4;$lk@x=&*#gV5m1t3h5_n|GGjw=u6|c^ZyPt~Dy@(Z!%JE0 zn1iII(TRz@ZaKCW^mw-5kZLJ`c6IY}SIBdyCf?)jy|jKvpZiz4FEy0S`^KT`^O&CO zGMc7*zR|I7;tt=EdxVw>@MBm>tpJz{s4Plbop5T23(6c;brR>Dc_Jxk_x#b*-od7F zICr~^+Re|8L|cL)4;-4RCACw28WIT;zmg9q%1)GSg!vial~MT?u2*FE2x&)-1Y-5| zXw72Vrj#HX*({NR!?NJZ>&+zn(h_17`&LO9aw^_c+8Rkv>MGxymO+VggK2o#8yOQC8d$nG3bdJcEWK2<=JIT zt!3H1DUrto(Gw>BS}mVuMoCo`K!EkDC6MDqe<~1a82j!h{7&h&0S0_@Fx%@*P}e(P z3H#6p*`JSKiqS%8W3ANfV&muVRgG16X7U~0Z~FR{i?VXNLpqz53Ca~F3kDitOHl~H z)*9%AFP634prvh7?KPC>#~JLEJMP_1uYq=j*KT${nLrySDp)GQ*h*(1veydz=Bgs# zUomtP>^O}$8}e3b;5s%gdPp@ZitqV{dIty!p-#hqeA=Ug&5|UCq=nwvug@ZLHhsua zOr=*UkdL4V@h=ObN+N$Ui6N*tug6KP4}8TU?n~OlY5!rOsX@)(VT^iLCrOzM9j-D8 zT)^N)-I0PTvSA!aagc6F-asNbr*JKm9d2)-*-Y5Fgw3 za8#qSuVN+PlOREPkb%jiyrDDi+$Q+`_It9p9tJ%*mDW1i<`A!sE+ zx*!40P0n|Kl!VMT9pTaHq701~A4R89k?9{;LQNb*Dhv8Bjm?T>R7f)C!87V#5T(1# zT}zQ(rCC~t+p5y)4XQ6$Y_5}hQB!5*Y|Kd+B2m{<&64${Ok*Q8_0nP-0PSwKxt#*8 zyfefWR#yHMsF*}3yqmOzUq1Ck{sF*BHSvsLwoHf$U)bVlUT|^~drZhjk)9>@ViR5D zQVx_8O3nt4Il>V?U8?XW4Z*7;3jMNQ#CC zEiJMCf#iQP*@XN_>IKXx;jVfI@XLfJI&=Ri$*-Ez%WQFp@=nsv_*@>-LPRGZ%jsuY zp7;2o@}({uX)VEvu+Gtrqq^E0zHTflHSWkHapoOx->$OH?xv+IO=(ZY|A4LN!HjiqVmzF3YxuT{zZA20|d%sC&A7DyU*Be66BS)(x>7=KwDlW zwU36CfhPRz9t{FfJ?@`t&{8S|Bzb(=S_;J_GO=qAej&3pwmvp4?g(!0%c3>(RnM&M z-vS8>Ww*u}fNvm&?xhMyHFQ+CTu_;BVUnXa0ootjYW3_hEbzyDQf-0!$9GtigSd~; zL5X7@TQ$KXWta%UsqdoRcbXjXu>rH6{(tH4E|3{iWwuxc)xI7c-q8#Z^>!hEt9^uK-=IxAGGnyG#nb5ysA@lMN=wy z2k15|Z5+17u@mWmT1xa^-vL&cA%*vW+tH`?_EnkUr-H`JdPKIn5gTL5It=JLDQSkR zl5}|UwtHK6L<){mdHH+E=Q{O69U}fN>N4R07zM^jZX?90@lCp>N`{%(H5F4ah_uiV z&)=Hdz|XD@gl^O9hCLdc$!^ZR_vQAz>FXM0!O__v2e$EI^uMg$?Vo%{ zHjK)KG!)E&lMVB)mPP(J<~tBDYGk>+1KN2$Mhwe}_y|*%7G-R{+7BcMCoVRDB*B!p zKHoC-&SnBNW*uRgW4;Q|fsZ%!n0t6u3+Jj<^QjZOPXo?)Zw~z@PKuMnYa!=+EZ~W} zJUMvge&?#nJ+w%6NWV5E+-uyC{LqYkh z?%`sw{U%FL)K2>8*tt;PE!9r(Nuxr-({iCR(TQZTj>N^^bGM7vug%`c{j%{lhJozI z!OPm%$fIU>Z0?1nheK-YVw=uiZb}c_pV%!G!zCXil-Hy-o?H;`b^^+I>KA&1 z)KcYI!%*UWH9?+P?pR@CtMrs_%S~N#|M;s-hZH>WtvwU?uYX}_io$l%OMwBUt%@J>*B0h!r zqh_7x61DuFs5q;rxSDX=HZH*>LAr6b;O+!>cM{ySaYC>_65QS0y`dW?xD(t7G_Jv& z|8gGA9rr%esMkIA!`@Zvn{z!}HD7W=w_BQ535DA)n(+W)Qx5|M(3X}=etnI7VB#`E z$-xKMs3OPkZ7=La=|Y1|&W~$1&GL5z=*6)jaq|7;3@0su8>g@?G1t;$FR{kQ(Mdlx z2c24m>MthC4w{?>CcW`?5q zJA}KbCb=0?dnjH>s(3A_M_QF*Ny9aT&0MMbcpKEYD`!IA#wYB7Z;c6;m2$XhH=C=9 zDC><1F;CqcBox?gBh~CRCrQ%g+zR~If41J}15bZUd4^mvA^f@Qzk&1O!QM6091*Gp z3vJLRUSxO|XP}tlkM>1!)i%rmxjkFtI!QN)RH523z4m3h3m(S2)*US*8|b^9@ynt# z9~COb3eZK~u9|bP3ENm*pu<42leddUHrCCveZRs*G;%NLaL@iM@f81ki4IrJiy$cQ zT3V}!5@LEI!Jp8$%SaQs|hgK28)bGBJ8L=|V`lvrg!>v_mD zX1*HCwYpHA72U6%{)4svO(KTRt&Q)L_zsh1qiIwdfcF-Xsb8X>EG*3F`Q~Y(6_!{zmroZJ;M{ft+pGAL>PK@Z;K9G}W2|@31TLY}`5}UX);iIxT^zDr)A5cbUt{^OJ#XJ|QJ-s! z3-WCZ>AA96F?59l>ZaM^1drWrL%00&>yz*A*m-km%sgr_p}Xq;0Ga46R?dC32vtjH zrfVNlR~3d|F9sbmy60086_ie0a_4OvQ(-nT&3`YBO(tGH_4=S9)rx4k(fE8!Wh|q( zF>>0;4&2JkVICjK28L*k@hDW1-^*>5A1lcEaX(-$R48z|>+Rf3=q7ve6@QjI;`&MD zEx4DMm~AXL3}T4@%qIV{FRJ;d^o6bpCN`i`_2dB?&`$7%5oa%I79?xR+He*|G6DXd zg*Xw7x_!nAng|5_>yv-t``$VZ9llI@$U8K{-!lFz{44}y57gc|<|;c_Xjyf${P~{p zltTST)m#3~ll+)Quj!h-kT<@a^GH(jetsZo43X|>2qmtBU+(e`0GKqOQcVT1|GZ~` zAr9$f1ecYJIHZPapxAmhcQv_DB+V5CqDD33q<6uiJKUrAA7~Lh5232U^ zb*hSgz+|bpU&ZVaG{nm*-FgkeOvsh4loJChx`~c4BSlAO_iQ(*Yxz0(?e{y|sIoA9 zw2<{y3`XA%OLhyA(fvwY)!YSaf%&E=6U6FJxT#BM&n?&vShJV*a%}ggRbsqNBjduvro-~Q3d2Xgs0jUy(Gj@(?Dgamlt}FT@1xILSDu>0t=tHMw zs#nu@M1$33GAB5*b!&ag2H#~Z@!jY1z#xez3Hl*niRg!?n+v7)mgSJwq@XgD-AvN= zpBT%rd-wmbD?|S)qFklg2In_>`uxW|ZcN{!m99R$q6nnBwZ4hr&( zOJSWnn=f(4;Hi#9y%xk2Q#^l|cVrbTfo7tyR3E6_y71&~Y}_~)i^;9abf*q;MGI)2 zM*eY9U9Kuqi*lvos1|Lpyu6#bseX!rS_Y0$)3%N!I-qkP^E`||nI(i9rrw^nnS&bQ zLGhj%ml4@o{abT!nx^bh0=o@oR0bDW3b~Yvha-ifeph>l-K z7uDkwniPwBQ{7ZCQf9y{MaFwME@xsJ?Okrq{)1V(S^v zC*sDkVZ_L~?2 zHcR>;$C+i|lpVNi@=9ReCWIklqp-p>M3dFDYh3`wR5v=a41Jg7 zN2?+q(rdPHlNMkr7$Fb~x^!95FEC&F50GFaSQ@EiOYUR${RfV8EYD(`i_rD+5!P~6 z_r^%PJWg?TJZn)~>-YD{ReqM~+09W`$WuWY!nfzTn|G& z5GjTzM7)GEtZ@a#?g~C{LMyj(DEbF%bimiKXx)pe!9TIM5;45S^3I5CRzHVK|6Zwa z`&qubvaEnd7OFV@v<@3j^8RMRd|m6Yl$G&yHeN~yUgqLh-C@qF z17h$ymnjFpvLRx>Og2~bgz__d;2P47YyeY?C;&nZRP|+kp_%2hPX~vZua=_dq=znnDsOtm zl41kqH9ur<$is~!F}K|OL)3m}g#pM^; zxx|m61E@-x61+c+tjA{K)>!&ontUel`I^<{eQZi<5;+>NZZT(_{4zUxq*y1BIg%x# z^_##X9^*Cnf^1wLEm$3{s$x}6wNI6xmoE*Q+BKQT99d#~paCF2|FMc_bXx-752xE_ zIbPkN;;5QIza0sPb8;De;OuiSDHrmzO7QJf;Pv*;=!<*O!=fwv*fCJMPv0EAWKQ8pUBPPFYV~= zX_#P)Vvm;jF3%D8!JcwXze$SO-1@`xe)&pe#?dX;Dx{Zvj(;PAZ`N48Y0SA2R&7eI znrYDWhnxjha5vpU)>9Ra3+c`~7rYdtbm`Ek20fvr;*LxAr*sf)!Wy9xO1G-^oj_xCg*+_HDiHfp8sBn#^YZmLmm1G&;BMzdr_AsPIK=+*4NtR zTvPe_a*EuFMNXab>p&#vvFfmIQfjXQJ|Ka4(ji|rQaM#Vg*cig>QK;SzDD3navFKf zDVRRvoz*D%81KAJDY|NAYN*y^G(pE*fnrJ$itQ=fncLAtX{v1qgI=B)_;D%ibK5e4 zkydNPA;-Ct_qv4#{)L~X-0mjctGFwYVB%WH3k}$QRi0s3q^3q7p==i;5porzp3nu91G;teR^Iud-br!Z+IG&IbL={59 z9oL^~eN-zbLeL;Jg5aN0QYL`yVw?xXYi}mGl1reJ9~|f z(QOS+pJ^8(GThzzLto8Fgg_3;RlK1K75dc?0u)Y<(`_N%OYg9z@8`^ z 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 o3jbU>{lbHR;lTc_0e>x|4QjCe2X5;$I{*Lx delta 11132 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 From 38418677f86034011532e2d0413081532e52e5f5 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 9 Apr 2014 20:44:32 +0700 Subject: [PATCH 076/146] Fix unit test error --- src/PhpWord/Reader/Word2007.php | 7 ++++--- tests/PhpWord/Tests/StyleTest.php | 2 +- tests/PhpWord/Tests/TOCTest.php | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 422258f2..f2687924 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -403,13 +403,14 @@ class Word2007 extends AbstractReader implements ReaderInterface $parent->addTextBreak(null, $pStyle); } else { if ($runLinkCount > 1) { - $textContainer = &$parent->addTextRun($pStyle); + $textrun = $parent->addTextRun($pStyle); + $textParent = &$textrun; } else { - $textContainer = &$parent; + $textParent = &$parent; } $nodes = $xmlReader->getElements('*', $domNode); foreach ($nodes as $node) { - $this->readRun($xmlReader, $node, $textContainer, $docPart, $pStyle); + $this->readRun($xmlReader, $node, $textParent, $docPart, $pStyle); } } } diff --git a/tests/PhpWord/Tests/StyleTest.php b/tests/PhpWord/Tests/StyleTest.php index bf28fa88..4ace72b6 100644 --- a/tests/PhpWord/Tests/StyleTest.php +++ b/tests/PhpWord/Tests/StyleTest.php @@ -24,7 +24,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase public function testStyles() { $paragraph = array('align' => 'center'); - $font = array('italic' => true); + $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); $styles = array('Paragraph' => 'Paragraph', 'Font' => 'Font', 'Link' => 'Font', 'Table' => 'Table', diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 7092795a..5417bb44 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -28,7 +28,7 @@ class TOCTest extends \PHPUnit_Framework_TestCase 'tabLeader' => \PhpOffice\PhpWord\Style\TOC::TABLEADER_DOT, 'indent' => 200, ); - $object = new TOC(array('size' => 11), array('tabPos' => $expected['tabPos'])); + $object = new TOC(array('_size' => 11), array('_tabPos' => $expected['tabPos'])); $tocStyle = $object->getStyleTOC(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\TOC', $tocStyle); From f8373812386158a72bd181e4aa01ab23cf7ac440 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Wed, 9 Apr 2014 21:35:55 +0700 Subject: [PATCH 077/146] Ability to add Endnotes --- CHANGELOG.md | 4 +- README.md | 1 + docs/elements.rst | 17 ++-- docs/intro.rst | 29 +++--- src/PhpWord/Element/AbstractElement.php | 34 ++++++- src/PhpWord/Element/Endnote.php | 31 ++++++ src/PhpWord/Element/Footnote.php | 2 +- src/PhpWord/Endnotes.php | 98 +++++++++++++++++++ src/PhpWord/{Footnote.php => Footnotes.php} | 26 ++--- src/PhpWord/Media.php | 55 ++++++----- src/PhpWord/Reader/Word2007.php | 45 +++++---- src/PhpWord/Shared/XMLReader.php | 4 +- src/PhpWord/Style.php | 2 +- src/PhpWord/Style/Image.php | 1 - src/PhpWord/Writer/ODText.php | 14 +-- src/PhpWord/Writer/ODText/Manifest.php | 5 +- src/PhpWord/Writer/ODText/Mimetype.php | 5 +- src/PhpWord/Writer/Word2007.php | 52 +++++++--- src/PhpWord/Writer/Word2007/Base.php | 45 +++++++-- .../Word2007/{Footnotes.php => Notes.php} | 62 +++++++----- tests/PhpWord/Tests/EndnotesTest.php | 39 ++++++++ tests/PhpWord/Tests/FootnoteTest.php | 39 -------- tests/PhpWord/Tests/FootnotesTest.php | 39 ++++++++ .../{FootnotesTest.php => NotesTest.php} | 5 +- tests/PhpWord/Tests/Writer/Word2007Test.php | 21 ++-- 25 files changed, 470 insertions(+), 205 deletions(-) create mode 100644 src/PhpWord/Element/Endnote.php create mode 100644 src/PhpWord/Endnotes.php rename src/PhpWord/{Footnote.php => Footnotes.php} (81%) rename src/PhpWord/Writer/Word2007/{Footnotes.php => Notes.php} (65%) create mode 100644 tests/PhpWord/Tests/EndnotesTest.php delete mode 100644 tests/PhpWord/Tests/FootnoteTest.php create mode 100644 tests/PhpWord/Tests/FootnotesTest.php rename tests/PhpWord/Tests/Writer/Word2007/{FootnotesTest.php => NotesTest.php} (86%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5e043b5..72b93e7b 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.9.2 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. ### Features @@ -28,6 +28,7 @@ This release marked heavy refactorings on internal code structure with the creat - Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 - General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 - Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table - @ivanlanin +- Endnote: Ability to add endnotes - @ivanlanin ### Bugfixes @@ -59,6 +60,7 @@ This release marked heavy refactorings on internal code structure with the creat - General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 - Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 - Writer: New 'ODText\Base` class - @ivanlanin GH-187 +- General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin ## 0.9.1 - 27 Mar 2014 diff --git a/README.md b/README.md index 8470aa90..3a9a4615 100755 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your * Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) * Insert list items as bulleted, numbered, or multilevel * Insert hyperlinks +* Insert footnotes and endnotes * Create document from templates * Use XSL 1.0 style sheets to transform main document part of OOXML template * ... and many more features on progress diff --git a/docs/elements.rst b/docs/elements.rst index 428db6e2..62ee007f 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -37,7 +37,9 @@ the containers while the rows lists the elements. +-----+---------------+---------+--------+--------+------+----------+----------+ | 14 | Footnote | v | \- | \- | v\*\*| v\*\* | \- | +-----+---------------+---------+--------+--------+------+----------+----------+ -| 15 | CheckBox | v | v | v | v | ? | ? | +| 15 | Endnote | v | \- | \- | v\*\*| v\*\* | \- | ++-----+---------------+---------+--------+--------+------+----------+----------+ +| 16 | CheckBox | v | v | v | v | ? | ? | +-----+---------------+---------+--------+--------+------+----------+----------+ Legend: @@ -376,12 +378,13 @@ Options for ``$tocStyle``: twips. - ``indent`` The indent factor of the titles in twips. -Footnotes ---------- +Footnotes & endnotes +-------------------- -You can create footnotes in texts or textruns, but it's recommended to -use textrun to have better layout. You can use ``addText``, ``addLink``, -and ``addTextBreak`` on a footnote. +You can create footnotes with ``addFootnote`` and endnotes with ``addEndnote`` +in texts or textruns, but it's recommended to use textrun to have better layout. +You can use ``addText``, ``addLink``, ``addTextBreak``, ``addImage``, +``addObject`` on footnotes and endnotes. On textrun: @@ -396,6 +399,8 @@ On textrun: $footnote->addTextBreak(); $footnote->addText('And text break.'); $textrun->addText('Trailing text.'); + $endnote = $textrun->addEndnote(); + $endnote->addText('Endnote put at the end'); On text: diff --git a/docs/intro.rst b/docs/intro.rst index a30dc553..0f1f3d74 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -48,6 +48,7 @@ Features rowspan, colspan) - Insert list items as bulleted, numbered, or multilevel - Insert hyperlinks +- Insert footnotes and endnotes - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template @@ -90,8 +91,6 @@ Writers + +-----------------------+--------+-------+-------+ | | Image | ✓ | | | + +-----------------------+--------+-------+-------+ -| | MemoryImage | ✓ | | | -+ +-----------------------+--------+-------+-------+ | | Object | ✓ | | | + +-----------------------+--------+-------+-------+ | | Watermark | ✓ | | | @@ -103,6 +102,8 @@ Writers | | Footer | ✓ | | | + +-----------------------+--------+-------+-------+ | | Footnote | ✓ | | | ++ +-----------------------+--------+-------+-------+ +| | Endnote | ✓ | | | +-------------------------+-----------------------+--------+-------+-------+ | **Graphs** | 2D basic graphs | | | | + +-----------------------+--------+-------+-------+ @@ -126,11 +127,11 @@ Readers +-------------------------------------------------+--------+-------+-------+ | Features | DOCX | ODT | RTF | +=========================+=======================+========+=======+=======+ -| **Document Properties** | Standard | | | | +| **Document Properties** | Standard | ✓ | | | + +-----------------------+--------+-------+-------+ -| | Extended | | | | +| | Extended | ✓ | | | + +-----------------------+--------+-------+-------+ -| | UserDefined | | | | +| | UserDefined | ✓ | | | +-------------------------+-----------------------+--------+-------+-------+ | **Element Type** | Text | ✓ | | | + +-----------------------+--------+-------+-------+ @@ -138,33 +139,33 @@ Readers + +-----------------------+--------+-------+-------+ | | Title | | | | + +-----------------------+--------+-------+-------+ -| | Link | | | | +| | Link | ✓ | | | + +-----------------------+--------+-------+-------+ -| | Preserve Text | | | | +| | Preserve Text | ✓ | | | + +-----------------------+--------+-------+-------+ | | Text Break | ✓ | | | + +-----------------------+--------+-------+-------+ -| | Page Break | | | | +| | Page Break | ✓ | | | + +-----------------------+--------+-------+-------+ | | List | | | | + +-----------------------+--------+-------+-------+ -| | Table | | | | +| | Table | ✓ | | | + +-----------------------+--------+-------+-------+ | | Image | | | | + +-----------------------+--------+-------+-------+ -| | MemoryImage | | | | -+ +-----------------------+--------+-------+-------+ | | Object | | | | + +-----------------------+--------+-------+-------+ | | Watermark | | | | + +-----------------------+--------+-------+-------+ | | Table of Contents | | | | + +-----------------------+--------+-------+-------+ -| | Header | | | | +| | Header | ✓ | | | + +-----------------------+--------+-------+-------+ -| | Footer | | | | +| | Footer | ✓ | | | + +-----------------------+--------+-------+-------+ -| | Footnote | | | | +| | Footnote | ✓ | | | ++ +-----------------------+--------+-------+-------+ +| | Endnote | ✓ | | | +-------------------------+-----------------------+--------+-------+-------+ | **Graphs** | 2D basic graphs | | | | + +-----------------------+--------+-------+-------+ diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 8ee75b90..56505cbc 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -13,7 +13,8 @@ use PhpOffice\PhpWord\Exception\InvalidObjectException; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Footnote as FootnoteCollection; +use PhpOffice\PhpWord\Footnotes; +use PhpOffice\PhpWord\Endnotes; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Element\Element; use PhpOffice\PhpWord\Element\Text; @@ -27,6 +28,7 @@ use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Object; use PhpOffice\PhpWord\Element\Footnote as FootnoteElement; +use PhpOffice\PhpWord\Element\Endnote; use PhpOffice\PhpWord\Element\CheckBox; /** @@ -37,7 +39,7 @@ use PhpOffice\PhpWord\Element\CheckBox; abstract class AbstractElement { /** - * Container type section|header|footer|cell|textrun|footnote + * Container type section|header|footer|cell|textrun|footnote|endnote * * @var string */ @@ -99,7 +101,7 @@ abstract class AbstractElement $this->checkValidity('text'); // Reset paragraph style for footnote and textrun. They have their own - if (in_array($this->container, array('footnote', 'textrun'))) { + if (in_array($this->container, array('textrun', 'footnote', 'endnote'))) { $paragraphStyle = null; } @@ -323,7 +325,7 @@ abstract class AbstractElement $this->checkValidity('footnote'); $footnote = new FootnoteElement($paragraphStyle); - $rId = FootnoteCollection::addFootnoteElement($footnote); + $rId = Footnotes::addElement($footnote); $footnote->setDocPart('footnote', $this->getDocPartId()); $footnote->setRelationId($rId); @@ -332,6 +334,26 @@ abstract class AbstractElement return $footnote; } + /** + * Add endnote element + * + * @param mixed $paragraphStyle + * @return Endnote + */ + public function addEndnote($paragraphStyle = null) + { + $this->checkValidity('endnote'); + + $endnote = new Endnote($paragraphStyle); + $rId = Endnotes::addElement($endnote); + + $endnote->setDocPart('endnote', $this->getDocPartId()); + $endnote->setRelationId($rId); + $this->elements[] = $endnote; + + return $endnote; + } + /** * Add a CheckBox Element * @@ -469,7 +491,7 @@ abstract class AbstractElement private function checkValidity($method) { // Valid containers for each element - $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote'); + $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote', 'endnote'); $validContainers = array( 'text' => $allContainers, 'link' => $allContainers, @@ -481,6 +503,7 @@ abstract class AbstractElement 'checkbox' => array('section', 'header', 'footer', 'cell'), 'table' => array('section', 'header', 'footer'), 'footnote' => array('section', 'textrun', 'cell'), + 'endnote' => array('section', 'textrun', 'cell'), 'preservetext' => array('header', 'footer', 'cell'), 'title' => array('section'), ); @@ -489,6 +512,7 @@ abstract class AbstractElement $validContainerInContainers = array( 'preservetext' => array(array('cell'), array('header', 'footer')), 'footnote' => array(array('cell', 'textrun'), array('section')), + 'endnote' => array(array('cell', 'textrun'), array('section')), ); // Check if a method is valid for current container diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php new file mode 100644 index 00000000..084119c2 --- /dev/null +++ b/src/PhpWord/Element/Endnote.php @@ -0,0 +1,31 @@ +container = 'endnote'; + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + } +} diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index d35dd548..4dcc1fd4 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -21,7 +21,7 @@ class Footnote extends AbstractElement * * @var string|Paragraph */ - private $paragraphStyle; + protected $paragraphStyle; /** * Create new instance diff --git a/src/PhpWord/Endnotes.php b/src/PhpWord/Endnotes.php new file mode 100644 index 00000000..86c923d3 --- /dev/null +++ b/src/PhpWord/Endnotes.php @@ -0,0 +1,98 @@ +getIsMemImage(); - $extension = $image->getImageExtension(); - $mediaData['imageExtension'] = $extension; - $mediaData['imageType'] = $image->getImageType(); - if ($isMemImage) { - $mediaData['isMemImage'] = true; - $mediaData['createFunction'] = $image->getImageCreateFunction(); - $mediaData['imageFunction'] = $image->getImageFunction(); - } - $target = "media/{$container}_image{$mediaTypeCount}.{$extension}"; - // Objects - } elseif ($mediaType == 'object') { - $file = "oleObject{$mediaTypeCount}.bin"; - $target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin"; - // Links - } elseif ($mediaType == 'link') { - $target = $source; + switch ($mediaType) { + // Images + case 'image': + if (is_null($image)) { + throw new Exception('Image object not assigned.'); + } + $isMemImage = $image->getIsMemImage(); + $extension = $image->getImageExtension(); + $mediaData['imageExtension'] = $extension; + $mediaData['imageType'] = $image->getImageType(); + if ($isMemImage) { + $mediaData['isMemImage'] = true; + $mediaData['createFunction'] = $image->getImageCreateFunction(); + $mediaData['imageFunction'] = $image->getImageFunction(); + } + $target = "media/{$container}_image{$mediaTypeCount}.{$extension}"; + break; + + // Objects + case 'object': + $target = "embeddings/{$container}_oleObject{$mediaTypeCount}.bin"; + break; + + // Links + case 'link': + $target = $source; + break; } $mediaData['source'] = $source; @@ -89,7 +94,7 @@ class Media /** * Get media elements count * - * @param string $container section|headerx|footerx|footnote + * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @return integer * @since 0.9.2 @@ -116,7 +121,7 @@ class Media /** * Get media elements * - * @param string $container section|headerx|footerx|footnote + * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @return array * @since 0.9.2 diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index f2687924..36c81c3b 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -12,8 +12,8 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Footnote; +use PhpOffice\PhpWord\Endnotes; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Element\Section; @@ -44,7 +44,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * Loads PhpWord from file * * @param string $filename - * @return PhpWord|null + * @return PhpWord */ public function load($filename) { @@ -96,7 +96,8 @@ class Word2007 extends AbstractReader implements ReaderInterface break; case 'footnotes': - $this->readFootnotes($filename, $rel['target']); + case 'endnotes': + $this->readNotes($filename, $rel['target'], $rel['type']); break; } } @@ -147,14 +148,13 @@ class Word2007 extends AbstractReader implements ReaderInterface $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { - $nodeName = $node->nodeName; - if (!array_key_exists($nodeName, $mapping)) { + if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $method = $mapping[$nodeName]; + $method = $mapping[$node->nodeName]; $value = $node->nodeValue == '' ? null : $node->nodeValue; - if (array_key_exists($nodeName, $callbacks)) { - $value = $callbacks[$nodeName]($value); + if (array_key_exists($node->nodeName, $callbacks)) { + $value = $callbacks[$node->nodeName]($value); } if (method_exists($docProps, $method)) { $docProps->$method($value); @@ -253,7 +253,7 @@ class Word2007 extends AbstractReader implements ReaderInterface if (is_null($name)) { $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); } - $default = ($xmlReader->getAttribute('w:default', $node) == 1); + // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { case 'paragraph': $pStyle = $this->readParagraphStyle($xmlReader, $node); @@ -321,14 +321,16 @@ class Word2007 extends AbstractReader implements ReaderInterface } /** - * Read footnotes.xml + * Read (footnotes|endnotes).xml * * @param string $filename * @param string $xmlFile */ - private function readFootnotes($filename, $xmlFile) + private function readNotes($filename, $xmlFile, $notesType = 'footnotes') { - $footnotes = Footnote::getElements(); + $notesType = ($notesType == 'endnotes') ? 'endnotes' : 'footnotes'; + $collectionClass = 'PhpOffice\\PhpWord\\' . ucfirst($notesType); + $collection = $collectionClass::getElements(); $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($filename, $xmlFile); @@ -339,14 +341,14 @@ class Word2007 extends AbstractReader implements ReaderInterface $type = $xmlReader->getAttribute('w:type', $node); // Avoid w:type "separator" and "continuationSeparator" - // Only look for without w:type attribute - if (is_null($type) && array_key_exists($id, $footnotes)) { - $footnote = $footnotes[$id]; + // Only look for or without w:type attribute + if (is_null($type) && array_key_exists($id, $collection)) { + $element = $collection[$id]; $pNodes = $xmlReader->getElements('w:p/*', $node); foreach ($pNodes as $pNode) { - $this->readRun($xmlReader, $pNode, $footnote, 'footnotes'); + $this->readRun($xmlReader, $pNode, $element, $notesType); } - Footnote::setElement($id, $footnote); + $collectionClass::setElement($id, $element); } } } @@ -445,6 +447,10 @@ class Word2007 extends AbstractReader implements ReaderInterface if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { $parent->addFootnote(); + // Endnote + } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { + $parent->addEndnote(); + // Image } elseif ($xmlReader->elementExists('w:pict', $domNode)) { $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); @@ -457,7 +463,7 @@ class Word2007 extends AbstractReader implements ReaderInterface // Object } elseif ($xmlReader->elementExists('w:object', $domNode)) { $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject'); - $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); + // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { $textContent = ""; @@ -489,7 +495,6 @@ class Word2007 extends AbstractReader implements ReaderInterface $table = $parent->addTable($tblStyle); $tblNodes = $xmlReader->getElements('*', $domNode); foreach ($tblNodes as $tblNode) { - $tblNodeName = $tblNode->nodeName; if ($tblNode->nodeName == 'w:tblGrid') { // Column // @todo Do something with table columns @@ -745,7 +750,7 @@ class Word2007 extends AbstractReader implements ReaderInterface if (!array_key_exists($node->nodeName, $mapping)) { continue; } - $property = $mapping[$node->nodeName]; + // $property = $mapping[$node->nodeName]; switch ($node->nodeName) { case 'w:tblCellMar': foreach ($margins as $side) { diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 0f6ce3f0..e5b5facc 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -105,7 +105,7 @@ class XMLReader * @param string $path * @return string|null */ - public function getAttribute($attribute, \DOMElement $contextNode, $path = null) + public function getAttribute($attribute, \DOMNode $contextNode, $path = null) { if (is_null($path)) { $return = $contextNode->getAttribute($attribute); @@ -154,7 +154,7 @@ class XMLReader * Element exists * * @param string $path - * @return \DOMNodeList + * @return boolean */ public function elementExists($path, \DOMNode $contextNode) { diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 3c2eef09..5afbb91b 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -109,7 +109,7 @@ class Style /** * Get all styles * - * @return Font[] + * @return array */ public static function getStyles() { diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 49060607..f21e6674 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -192,7 +192,6 @@ class Image extends AbstractStyle break; default: throw new \InvalidArgumentException('Wrapping style does not exists'); - break; } return $this; } diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 4a4b1cbb..50064708 100755 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -48,6 +48,7 @@ class ODText extends AbstractWriter implements WriterInterface * * @param string $filename * @throws Exception + * @todo Not in \ZipArchive::CM_STORE mode */ public function save($filename = null) { @@ -56,20 +57,11 @@ class ODText extends AbstractWriter implements WriterInterface $objZip = $this->getZipArchive($filename); // Add mimetype to ZIP file - //@todo Not in \ZipArchive::CM_STORE mode - $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype($this->phpWord)); - - // Add content.xml to ZIP file + $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype()); $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord)); - - // Add meta.xml to ZIP file $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord)); - - // Add styles.xml to ZIP file $objZip->addFromString('styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); - - // Add META-INF/manifest.xml - $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->phpWord)); + $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest()); // Close file if ($objZip->close() === false) { diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php index b82a6041..220834c4 100755 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ b/src/PhpWord/Writer/ODText/Manifest.php @@ -9,8 +9,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\PhpWord; - /** * ODText manifest part writer */ @@ -19,10 +17,9 @@ class Manifest extends AbstractWriterPart /** * Write Manifest file to XML format * - * @param PhpWord $phpWord * @return string XML Output */ - public function writeManifest(PhpWord $phpWord = null) + public function writeManifest() { // Create XML writer $xmlWriter = $this->getXmlWriter(); diff --git a/src/PhpWord/Writer/ODText/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php index b8bc6539..269c377f 100644 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ b/src/PhpWord/Writer/ODText/Mimetype.php @@ -9,8 +9,6 @@ namespace PhpOffice\PhpWord\Writer\ODText; -use PhpOffice\PhpWord\PhpWord; - /** * ODText mimetype part writer */ @@ -19,10 +17,9 @@ class Mimetype extends AbstractWriterPart /** * Write Mimetype to Text format * - * @param PhpWord $phpWord * @return string Text Output */ - public function writeMimetype(PhpWord $phpWord = null) + public function writeMimetype() { return 'application/vnd.oasis.opendocument.text'; } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index c89f09ba..b44708a3 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -11,7 +11,6 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; @@ -19,7 +18,7 @@ use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\DocProps; use PhpOffice\PhpWord\Writer\Word2007\Document; use PhpOffice\PhpWord\Writer\Word2007\Footer; -use PhpOffice\PhpWord\Writer\Word2007\Footnotes; +use PhpOffice\PhpWord\Writer\Word2007\Notes; use PhpOffice\PhpWord\Writer\Word2007\Header; use PhpOffice\PhpWord\Writer\Word2007\Styles; @@ -60,7 +59,8 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->writerParts['styles'] = new Styles(); $this->writerParts['header'] = new Header(); $this->writerParts['footer'] = new Footer(); - $this->writerParts['footnotes'] = new Footnotes(); + $this->writerParts['footnotes'] = new Notes(); + $this->writerParts['endnotes'] = new Notes(); foreach ($this->writerParts as $writer) { $writer->setParentWriter($this); } @@ -105,17 +105,8 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->addHeaderFooterContent($section, $objZip, 'footer', $rId); } - // Add footnotes media files, relations, and contents - if (Footnote::countFootnoteElements() > 0) { - $footnoteMedia = Media::getElements('footnote'); - $this->addFilesToPackage($objZip, $footnoteMedia); - if (!empty($footnoteMedia)) { - $objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('rels')->writeMediaRels($footnoteMedia)); - } - $objZip->addFromString('word/footnotes.xml', $this->getWriterPart('footnotes')->writeFootnotes(Footnote::getFootnoteElements())); - $this->cTypes['override']["/word/footnotes.xml"] = 'footnotes'; - $this->docRels[] = array('target' => 'footnotes.xml', 'type' => 'footnotes', 'rID' => ++$rId); - } + $this->addNotes($objZip, $rId, 'footnote'); + $this->addNotes($objZip, $rId, 'endnote'); // Write dynamic files $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes($this->cTypes)); @@ -199,7 +190,8 @@ class Word2007 extends AbstractWriter implements WriterInterface if (!empty($media)) { $this->addFilesToPackage($objZip, $media); } - $objZip->addFromString("word/_rels/{$file}.xml.rels", $this->getWriterPart('rels')->writeMediaRels($media)); + $relsFile = "word/_rels/{$file}.xml.rels"; + $objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media)); } } } @@ -227,4 +219,34 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId); } } + + /** + * Add footnotes/endnotes + * + * @param mixed $objZip + * @param string $elmType + * @param integer $rId + */ + private function addNotes($objZip, &$rId, $notesType = 'footnote') + { + $notesType = ($notesType == 'endnote') ? 'endnote' : 'footnote'; + $notesTypes = "{$notesType}s"; + $collection = 'PhpOffice\\PhpWord\\' . ucfirst($notesTypes); + $xmlFile = "{$notesTypes}.xml"; + $relsFile = "word/_rels/{$xmlFile}.rels"; + $xmlPath = "word/{$xmlFile}"; + + // Add footnotes media files, relations, and contents + if ($collection::countElements() > 0) { + $media = Media::getElements($notesType); + $elements = $collection::getElements(); + $this->addFilesToPackage($objZip, $media); + if (!empty($media)) { + $objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media)); + } + $objZip->addFromString($xmlPath, $this->getWriterPart($notesTypes)->writeNotes($elements, $notesTypes)); + $this->cTypes['override']["/{$xmlPath}"] = $notesTypes; + $this->docRels[] = array('target' => $xmlFile, 'type' => $notesTypes, 'rID' => ++$rId); + } + } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 12291694..4fd38b57 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -23,6 +23,7 @@ use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Image; use PhpOffice\PhpWord\Element\Object; use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Element\Endnote; use PhpOffice\PhpWord\Element\CheckBox; use PhpOffice\PhpWord\Shared\String; use PhpOffice\PhpWord\Shared\XMLWriter; @@ -623,6 +624,33 @@ class Base extends AbstractWriterPart } } + /** + * Write endnote element which links to the actual content in endnotes.xml + * + * @param XMLWriter $xmlWriter + * @param Endnote $endnote + * @param boolean $withoutP + */ + protected function writeEndnote(XMLWriter $xmlWriter, Endnote $endnote, $withoutP = false) + { + if (!$withoutP) { + $xmlWriter->startElement('w:p'); + } + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', 'EndnoteReference'); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr + $xmlWriter->startElement('w:endnoteReference'); + $xmlWriter->writeAttribute('w:id', $endnote->getRelationId()); + $xmlWriter->endElement(); // w:endnoteReference + $xmlWriter->endElement(); // w:r + if (!$withoutP) { + $xmlWriter->endElement(); // w:p + } + } + /** * Write CheckBox * @@ -1132,9 +1160,10 @@ class Base extends AbstractWriterPart 'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Title', 'PageBreak', 'TOC')), 'Header' => array_merge($elmMainCell, array('Table', 'PreserveText')), 'Footer' => array_merge($elmMainCell, array('Table', 'PreserveText')), - 'Cell' => array_merge($elmMainCell, array('PreserveText', 'Footnote')), - 'TextRun' => array_merge($elmCommon, array('Footnote')), + 'Cell' => array_merge($elmMainCell, array('PreserveText', 'Footnote', 'Endnote')), + 'TextRun' => array_merge($elmCommon, array('Footnote', 'Endnote')), 'Footnote' => $elmCommon, + 'Endnote' => $elmCommon, ); $containerName = get_class($container); $containerName = substr($containerName, strrpos($containerName, '\\') + 1); @@ -1158,10 +1187,14 @@ class Base extends AbstractWriterPart $method = "writeWatermark"; } } - if (in_array($containerName, array('TextRun', 'Footnote'))) { - $this->$method($xmlWriter, $element, true); - } else { - $this->$method($xmlWriter, $element); + switch ($containerName) { + case 'TextRun': + case 'Footnote': + case 'Endnote': + $this->$method($xmlWriter, $element, true); + break; + default: + $this->$method($xmlWriter, $element); } } } diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Notes.php similarity index 65% rename from src/PhpWord/Writer/Word2007/Footnotes.php rename to src/PhpWord/Writer/Word2007/Notes.php index ac85929d..96393b4c 100644 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ b/src/PhpWord/Writer/Word2007/Notes.php @@ -10,27 +10,30 @@ namespace PhpOffice\PhpWord\Writer\Word2007; use PhpOffice\PhpWord\Element\Footnote; +use PhpOffice\PhpWord\Element\Endnote; use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 footnotes part writer */ -class Footnotes extends Base +class Notes extends Base { /** - * Write word/footnotes.xml + * Write word/(footnotes|endnotes).xml * - * @param array $allFootnotesCollection + * @param array $elements + * @param string $notesTypes */ - public function writeFootnotes($allFootnotesCollection) + public function writeNotes($elements, $notesTypes = 'footnotes') { - // Create XML writer + $isFootnote = $notesTypes == 'footnotes'; + $rootNode = $isFootnote ? 'w:footnotes' : 'w:endnotes'; + $elementNode = $isFootnote ? 'w:footnote' : 'w:endnote'; $xmlWriter = $this->getXmlWriter(); // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('w:footnotes'); - + $xmlWriter->startElement($rootNode); $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); @@ -42,7 +45,7 @@ class Footnotes extends Base $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); // Separator and continuation separator - $xmlWriter->startElement('w:footnote'); + $xmlWriter->startElement($elementNode); $xmlWriter->writeAttribute('w:id', -1); $xmlWriter->writeAttribute('w:type', 'separator'); $xmlWriter->startElement('w:p'); @@ -51,8 +54,8 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:separator $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote - $xmlWriter->startElement('w:footnote'); + $xmlWriter->endElement(); // $elementNode + $xmlWriter->startElement($elementNode); $xmlWriter->writeAttribute('w:id', 0); $xmlWriter->writeAttribute('w:type', 'continuationSeparator'); $xmlWriter->startElement('w:p'); @@ -61,42 +64,53 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:continuationSeparator $xmlWriter->endElement(); // w:r $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote + $xmlWriter->endElement(); // $elementNode + // Content - foreach ($allFootnotesCollection as $footnote) { - if ($footnote instanceof Footnote) { - $this->writeFootnote($xmlWriter, $footnote); + foreach ($elements as $element) { + if ($element instanceof Footnote || $element instanceof Endnote) { + $this->writeNote($xmlWriter, $element, null, $notesTypes); } } + $xmlWriter->endElement(); return $xmlWriter->getData(); } /** - * Write footnote content, overrides method in parent class + * Write note item * * @param XMLWriter $xmlWriter - * @param Footnote $footnote + * @param Footnote|Endnote $element * @param boolean $withoutP + * @param string $notesTypes */ - protected function writeFootnote(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) + protected function writeNote(XMLWriter $xmlWriter, $element, $withoutP = false, $notesTypes = 'footnotes') { - $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', $footnote->getRelationId()); + $isFootnote = ($notesTypes == 'footnotes'); + $elementNode = $isFootnote ? 'w:footnote' : 'w:endnote'; + $refNode = $isFootnote ? 'w:footnoteRef' : 'w:endnoteRef'; + $styleName = $isFootnote ? 'FootnoteReference' : 'EndnoteReference'; + + $xmlWriter->startElement($elementNode); + $xmlWriter->writeAttribute('w:id', $element->getRelationId()); $xmlWriter->startElement('w:p'); + // Paragraph style - $styleParagraph = $footnote->getParagraphStyle(); + $styleParagraph = $element->getParagraphStyle(); $this->writeInlineParagraphStyle($xmlWriter, $styleParagraph); + // Reference symbol $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:rPr'); $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', 'FootnoteReference'); + $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); // w:rStyle $xmlWriter->endElement(); // w:rPr - $xmlWriter->writeElement('w:footnoteRef'); + $xmlWriter->writeElement($refNode); $xmlWriter->endElement(); // w:r + // Empty space after refence symbol $xmlWriter->startElement('w:r'); $xmlWriter->startElement('w:t'); @@ -105,9 +119,9 @@ class Footnotes extends Base $xmlWriter->endElement(); // w:t $xmlWriter->endElement(); // w:r - $this->writeContainerElements($xmlWriter, $footnote); + $this->writeContainerElements($xmlWriter, $element); $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote + $xmlWriter->endElement(); // $elementNode } } diff --git a/tests/PhpWord/Tests/EndnotesTest.php b/tests/PhpWord/Tests/EndnotesTest.php new file mode 100644 index 00000000..a72e85f9 --- /dev/null +++ b/tests/PhpWord/Tests/EndnotesTest.php @@ -0,0 +1,39 @@ +assertEquals(1, $rId); + $this->assertEquals(1, count(Endnotes::getElements())); + $this->assertEquals($endnote2, Endnotes::getElement(1)); + $this->assertNull(Endnotes::getElement(2)); + + Endnotes::resetElements(); + $this->assertEquals(0, Endnotes::countElements()); + } +} diff --git a/tests/PhpWord/Tests/FootnoteTest.php b/tests/PhpWord/Tests/FootnoteTest.php deleted file mode 100644 index 6dcda73f..00000000 --- a/tests/PhpWord/Tests/FootnoteTest.php +++ /dev/null @@ -1,39 +0,0 @@ -assertEquals(1, $rId); - $this->assertEquals(1, count(Footnote::getElements())); - $this->assertEquals($footnote2, Footnote::getElement(1)); - $this->assertNull(Footnote::getElement(2)); - - Footnote::resetElements(); - $this->assertEquals(0, Footnote::countElements()); - } -} diff --git a/tests/PhpWord/Tests/FootnotesTest.php b/tests/PhpWord/Tests/FootnotesTest.php new file mode 100644 index 00000000..869c69a7 --- /dev/null +++ b/tests/PhpWord/Tests/FootnotesTest.php @@ -0,0 +1,39 @@ +assertEquals(1, $rId); + $this->assertEquals(1, count(Footnotes::getElements())); + $this->assertEquals($footnote2, Footnotes::getElement(1)); + $this->assertNull(Footnotes::getElement(2)); + + Footnotes::resetElements(); + $this->assertEquals(0, Footnotes::countElements()); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/NotesTest.php similarity index 86% rename from tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php rename to tests/PhpWord/Tests/Writer/Word2007/NotesTest.php index 11817962..f883314a 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/NotesTest.php @@ -12,12 +12,11 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Tests\TestHelperDOCX; /** - * Test class for PhpOffice\PhpWord\Writer\Word2007\Footnotes + * Test class for PhpOffice\PhpWord\Writer\Word2007\Notes * - * @coversDefaultClass \PhpOffice\PhpWord\Writer\Word2007\Footnotes * @runTestsInSeparateProcesses */ -class FootnotesTest extends \PHPUnit_Framework_TestCase +class NotesTest extends \PHPUnit_Framework_TestCase { /** * Executed before each method of the class diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index 38c2e6e7..5e990615 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -35,18 +35,19 @@ class Word2007Test extends \PHPUnit_Framework_TestCase $object = new Word2007(new PhpWord()); $writerParts = array( - 'ContentTypes', - 'Rels', - 'DocProps', - 'Document', - 'Styles', - 'Header', - 'Footer', - 'Footnotes', + 'ContentTypes' => 'ContentTypes', + 'Rels' => 'Rels', + 'DocProps' => 'DocProps', + 'Document' => 'Document', + 'Styles' => 'Styles', + 'Header' => 'Header', + 'Footer' => 'Footer', + 'Footnotes' => 'Notes', + 'Endnotes' => 'Notes', ); - foreach ($writerParts as $part) { + foreach ($writerParts as $part => $type) { $this->assertInstanceOf( - "PhpOffice\\PhpWord\\Writer\\Word2007\\{$part}", + "PhpOffice\\PhpWord\\Writer\\Word2007\\{$type}", $object->getWriterPart($part) ); $this->assertInstanceOf( From 5b4ed1099975754d591682966bc8b0d5a6462f90 Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 10 Apr 2014 11:06:39 +0400 Subject: [PATCH 078/146] [FIXED] Dockblock for https://github.com/PHPOffice/PHPWord/pull/187 --- src/PhpWord/Element/Section.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 0d7da0e5..6abbbf98 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -10,11 +10,8 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Element\Footer; -use PhpOffice\PhpWord\Element\Header; -use PhpOffice\PhpWord\Element\PageBreak; use PhpOffice\PhpWord\Style\Section as SectionSettings; +use PhpOffice\PhpWord\TOC; /** * Section @@ -177,8 +174,9 @@ class Section extends AbstractElement * Add header/footer * * @param string $type - * @param string $header + * @param boolean $header * @return Header|Footer + * @throws Exception * @since 0.9.2 */ private function addHeaderFooter($type = Header::AUTO, $header = true) From 4849bb271c4b125cca77e24364626312efdd9e2a Mon Sep 17 00:00:00 2001 From: Roman Syroeshko Date: Thu, 10 Apr 2014 11:47:26 +0400 Subject: [PATCH 079/146] [FIXED] Dockblocks for https://github.com/PHPOffice/PHPWord/pull/187. --- src/PhpWord/Writer/Word2007/Document.php | 25 ++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php index 9cc53375..0637c689 100644 --- a/src/PhpWord/Writer/Word2007/Document.php +++ b/src/PhpWord/Writer/Word2007/Document.php @@ -9,12 +9,13 @@ namespace PhpOffice\PhpWord\Writer\Word2007; -use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\TOC; -use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; +use PhpOffice\PhpWord\TOC; /** * Word2007 document part writer @@ -24,7 +25,9 @@ class Document extends Base /** * Write word/document.xml * - * @param PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @return string + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function writeDocument(PhpWord $phpWord = null) { @@ -81,8 +84,8 @@ class Document extends Base /** * Write begin section * - * @param XMLWriter $xmlWriter - * @param Section $section + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeSection(XMLWriter $xmlWriter, Section $section) { @@ -96,8 +99,8 @@ class Document extends Base /** * Write end section * - * @param XMLWriter $xmlWriter - * @param Section $section + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section */ private function writeEndSection(XMLWriter $xmlWriter, Section $section) { @@ -208,7 +211,8 @@ class Document extends Base /** * Write page break element * - * @param XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\PageBreak $pagebreak */ protected function writePageBreak(XMLWriter $xmlWriter, PageBreak $pagebreak) { @@ -224,7 +228,8 @@ class Document extends Base /** * Write TOC element * - * @param XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\TOC $toc */ protected function writeTOC(XMLWriter $xmlWriter, TOC $toc) { From 47669f501abfd2fd23346a814b2b68b43ee24390 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 16:16:22 +0700 Subject: [PATCH 080/146] Ability to create custom list #10 and to read list definition from DOCX --- CHANGELOG.md | 5 +- samples/Sample_14_ListItem.php | 73 ++-- src/PhpWord/Element/AbstractElement.php | 3 - src/PhpWord/Element/ListItem.php | 18 +- src/PhpWord/Endnotes.php | 1 - src/PhpWord/PhpWord.php | 11 + src/PhpWord/Reader/Word2007.php | 155 ++++++- src/PhpWord/Shared/XMLReader.php | 14 +- src/PhpWord/Style.php | 43 +- src/PhpWord/Style/AbstractStyle.php | 117 +++++- src/PhpWord/Style/ListItem.php | 220 +++++++++- src/PhpWord/Style/Numbering.php | 123 ++++++ src/PhpWord/Style/NumberingLevel.php | 378 ++++++++++++++++++ src/PhpWord/Template.php | 2 +- src/PhpWord/Writer/Word2007.php | 17 +- src/PhpWord/Writer/Word2007/Base.php | 4 +- src/PhpWord/Writer/Word2007/Notes.php | 5 +- src/PhpWord/Writer/Word2007/Numbering.php | 177 ++++++++ src/PhpWord/Writer/Word2007/Styles.php | 36 +- src/PhpWord/_staticDocParts/numbering.xml | 2 - .../Tests/Writer/Word2007/DocumentTest.php | 10 +- 21 files changed, 1276 insertions(+), 138 deletions(-) create mode 100644 src/PhpWord/Style/Numbering.php create mode 100644 src/PhpWord/Style/NumberingLevel.php create mode 100644 src/PhpWord/Writer/Word2007/Numbering.php delete mode 100644 src/PhpWord/_staticDocParts/numbering.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 72b93e7b..f96b4a63 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.9.2 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. ### Features @@ -27,8 +27,9 @@ This release marked heavy refactorings on internal code structure with the creat - Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 - Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 - General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 -- Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table - @ivanlanin +- Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, and list - @ivanlanin - Endnote: Ability to add endnotes - @ivanlanin +- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 ### Bugfixes diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 4cd9edea..45d9c1a7 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -8,41 +8,52 @@ $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code $section = $phpWord->addSection(); -// Add listitem elements -$section->addListItem('List Item 1', 0); -$section->addListItem('List Item 2', 0); -$section->addListItem('List Item 3', 0); -$section->addTextBreak(2); +// Style definition -// Add listitem elements -$section->addListItem('List Item 1', 0); -$section->addListItem('List Item 1.1', 1); -$section->addListItem('List Item 1.2', 1); -$section->addListItem('List Item 1.3 (styled)', 1, array('bold'=>true)); -$section->addListItem('List Item 1.3.1', 2); -$section->addListItem('List Item 1.3.2', 2); -$section->addTextBreak(2); - -// Add listitem elements -$listStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER); -$section->addListItem('List Item 1', 0, null, $listStyle); -$section->addListItem('List Item 2', 0, null, $listStyle); -$section->addListItem('List Item 3', 0, null, $listStyle); -$section->addTextBreak(2); - -// Add listitem elements $phpWord->addFontStyle('myOwnStyle', array('color'=>'FF0000')); $phpWord->addParagraphStyle('P-Style', array('spaceAfter'=>95)); -$listStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); -$section->addListItem('List Item 1', 0, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 2', 0, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 3', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 4', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 5', 2, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 6', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 7', 0, 'myOwnStyle', $listStyle, 'P-Style'); +$phpWord->addNumberingStyle( + 'multilevel', + array('type' => 'multilevel', 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) +); +$predefinedMultilevel = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); + +// Lists + +$section->addText('Multilevel list.'); +$section->addListItem('List Item I', 0, null, 'multilevel'); +$section->addListItem('List Item I.a', 1, null, 'multilevel'); +$section->addListItem('List Item I.b', 1, null, 'multilevel'); +$section->addListItem('List Item II', 0, null, 'multilevel'); +$section->addListItem('List Item II.a', 1, null, 'multilevel'); +$section->addListItem('List Item III', 0, null, 'multilevel'); +$section->addTextBreak(2); + +$section->addText('Basic simple bulleted list.'); +$section->addListItem('List Item 1'); +$section->addListItem('List Item 2'); +$section->addListItem('List Item 3'); +$section->addTextBreak(2); + +$section->addText('Continue from multilevel list above.'); +$section->addListItem('List Item IV', 0, null, 'multilevel'); +$section->addListItem('List Item IV.a', 1, null, 'multilevel'); +$section->addTextBreak(2); + +$section->addText('Multilevel predefined list.'); +$section->addListItem('List Item 1', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 2', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 3', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 4', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 5', 2, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 6', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 7', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addTextBreak(2); -// End code // Save file $name = basename(__FILE__, '.php'); diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 56505cbc..6562cb5b 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -469,9 +469,6 @@ abstract class AbstractElement { if (!is_null($styleValue) && is_array($styleValue)) { foreach ($styleValue as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } $styleObject->setStyleValue($key, $value); } $style = $styleObject; diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 5d19097e..39bd6b1b 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -44,15 +44,21 @@ class ListItem extends AbstractElement * * @param string $text * @param int $depth - * @param mixed $styleFont - * @param mixed $styleList - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param array|string|null $listStyle + * @param mixed $paragraphStyle */ - public function __construct($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) + public function __construct($text, $depth = 0, $fontStyle = null, $listStyle = null, $paragraphStyle = null) { - $this->textObject = new Text($text, $styleFont, $styleParagraph); + $this->textObject = new Text($text, $fontStyle, $paragraphStyle); $this->depth = $depth; - $this->style = $this->setStyle(new ListItemStyle(), $styleList, true); + + // Version >= 0.9.2 will pass numbering style name. Older version will use old method + if (!is_null($listStyle) && is_string($listStyle)) { + $this->style = new ListItemStyle($listStyle); + } else { + $this->style = $this->setStyle(new ListItemStyle(), $listStyle, true); + } } /** diff --git a/src/PhpWord/Endnotes.php b/src/PhpWord/Endnotes.php index 86c923d3..4a065b96 100644 --- a/src/PhpWord/Endnotes.php +++ b/src/PhpWord/Endnotes.php @@ -9,7 +9,6 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Element\Endnote; /** diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index c9bf4b63..2764a3a1 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -214,6 +214,17 @@ class PhpWord Style::addLinkStyle($styleName, $styles); } + /** + * Adds a numbering style + * + * @param string $styleName + * @param mixed $styles + */ + public function addNumberingStyle($styleName, $styles) + { + Style::addNumberingStyle($styleName, $styles); + } + /** * Get all sections * diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 36c81c3b..e03d28a0 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -11,8 +11,6 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; -use PhpOffice\PhpWord\Footnote; -use PhpOffice\PhpWord\Endnotes; use PhpOffice\PhpWord\DocumentProperties; use PhpOffice\PhpWord\Shared\XMLReader; use PhpOffice\PhpWord\Element\Section; @@ -52,6 +50,19 @@ class Word2007 extends AbstractReader implements ReaderInterface $this->readRelationships($filename); + + // Read styles and numbering first + foreach ($this->rels['document'] as $rId => $rel) { + switch ($rel['type']) { + case 'styles': + $this->readStyles($filename, $rel['target']); + break; + case 'numbering': + $this->readNumbering($filename, $rel['target']); + break; + } + } + // Read main relationship foreach ($this->rels['main'] as $rId => $rel) { switch ($rel['type']) { @@ -87,14 +98,9 @@ class Word2007 extends AbstractReader implements ReaderInterface } } - // Read document relationships + // Read footnotes and endnotes foreach ($this->rels['document'] as $rId => $rel) { switch ($rel['type']) { - - case 'styles': - $this->readStyles($filename, $rel['target']); - break; - case 'footnotes': case 'endnotes': $this->readNotes($filename, $rel['target'], $rel['type']); @@ -178,7 +184,6 @@ class Word2007 extends AbstractReader implements ReaderInterface $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { - $nodeName = $node->nodeName; $propertyName = $xmlReader->getAttribute('name', $node); $attributeNode = $xmlReader->getElement('*', $node); $attributeType = $attributeNode->nodeName; @@ -206,6 +211,7 @@ class Word2007 extends AbstractReader implements ReaderInterface $section = $this->phpWord->addSection(); foreach ($nodes as $node) { switch ($node->nodeName) { + case 'w:p': // Paragraph if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') { $section->addPageBreak(); // PageBreak @@ -221,9 +227,11 @@ class Word2007 extends AbstractReader implements ReaderInterface $section = $this->phpWord->addSection(); } break; + case 'w:tbl': // Table $this->readTable($xmlReader, $node, $section, 'document'); break; + case 'w:sectPr': // Last section $settings = $this->readSectionStyle($xmlReader, $node); $section->setSettings($settings); @@ -255,6 +263,7 @@ class Word2007 extends AbstractReader implements ReaderInterface } // $default = ($xmlReader->getAttribute('w:default', $node) == 1); switch ($type) { + case 'paragraph': $pStyle = $this->readParagraphStyle($xmlReader, $node); $fStyle = $this->readFontStyle($xmlReader, $node); @@ -264,12 +273,14 @@ class Word2007 extends AbstractReader implements ReaderInterface $this->phpWord->addFontStyle($name, $fStyle, $pStyle); } break; + case 'character': $fStyle = $this->readFontStyle($xmlReader, $node); if (!empty($fStyle)) { $this->phpWord->addFontStyle($name, $fStyle); } break; + case 'table': $tStyle = $this->readTableStyle($xmlReader, $node); if (!empty($tStyle)) { @@ -281,6 +292,98 @@ class Word2007 extends AbstractReader implements ReaderInterface } } + /** + * Read numbering.xml + * + * @param string $filename + * @param string $xmlFile + */ + private function readNumbering($filename, $xmlFile) + { + $abstracts = array(); + $numberings = array(); + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($filename, $xmlFile); + + // Abstract numbering definition + $nodes = $xmlReader->getElements('w:abstractNum'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node); + $abstracts[$abstractId] = array('levels' => array()); + $abstract = &$abstracts[$abstractId]; + $subnodes = $xmlReader->getElements('*', $node); + foreach ($subnodes as $subnode) { + switch ($subnode->nodeName) { + case 'w:multiLevelType': + $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode); + break; + case 'w:lvl': + $levelId = $xmlReader->getAttribute('w:ilvl', $subnode); + $abstract['levels'][$levelId] = $this->readNumberingLevel($xmlReader, $subnode, $levelId); + break; + } + } + } + } + + // Numbering instance definition + $nodes = $xmlReader->getElements('w:num'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $numId = $xmlReader->getAttribute('w:numId', $node); + $abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId'); + $numberings[$numId] = $abstracts[$abstractId]; + $numberings[$numId]['numId'] = $numId; + $subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node); + foreach ($subnodes as $subnode) { + $levelId = $xmlReader->getAttribute('w:ilvl', $subnode); + $overrides = $this->readNumberingLevel($xmlReader, $subnode, $levelId); + foreach ($overrides as $key => $value) { + $numberings[$numId]['levels'][$levelId][$key] = $value; + } + } + } + } + + // Push to Style collection + foreach ($numberings as $numId => $numbering) { + $this->phpWord->addNumberingStyle("PHPWordList{$numId}", $numbering); + } + } + + /** + * Read numbering level definition from w:abstractNum and w:num + * + * @param integer $levelId + * @return array + */ + private function readNumberingLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) + { + $level = array(); + + $level['level'] = $levelId; + $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start'); + $level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt'); + $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart'); + $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff'); + $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText'); + $level['align'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc'); + $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab'); + $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind'); + $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind'); + $level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts'); + $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts'); + + foreach ($level as $key => $value) { + if (is_null($value)) { + unset($level[$key]); + } + } + + return $level; + } + /** * Read header footer * @@ -325,6 +428,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @param string $filename * @param string $xmlFile + * @param string $notesType */ private function readNotes($filename, $xmlFile, $notesType = 'footnotes') { @@ -362,7 +466,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @todo Get font style for preserve text */ - private function readParagraph(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart) + private function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) { // Paragraph style $pStyle = null; @@ -396,6 +500,17 @@ class Word2007 extends AbstractReader implements ReaderInterface } $parent->addPreserveText($textContent, $fStyle, $pStyle); + // List item + } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { + $textContent = ''; + $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); + $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $pStyle); + // Text and TextRun } else { $runCount = $xmlReader->countElements('w:r', $domNode); @@ -421,13 +536,15 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read w:r * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode * @param mixed $parent * @param string $docPart * @param mixed $pStyle * * @todo Footnote paragraph style */ - private function readRun(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart, $pStyle = null) + private function readRun(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart, $pStyle = null) { if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { return; @@ -484,7 +601,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * @param mixed $parent * @param string $docPart */ - private function readTable(XMLReader $xmlReader, \DOMNode $domNode, &$parent, $docPart) + private function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) { // Table style $tblStyle = null; @@ -539,7 +656,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return array|null */ - private function readSectionStyle(XMLReader $xmlReader, \DOMNode $domNode) + private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) { $ret = null; $mapping = array( @@ -554,6 +671,7 @@ class Word2007 extends AbstractReader implements ReaderInterface } $property = $mapping[$node->nodeName]; switch ($node->nodeName) { + case 'w:type': $ret['breakType'] = $xmlReader->getAttribute('w:val', $node); break; @@ -598,7 +716,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return string|array|null */ - private function readParagraphStyle(XMLReader $xmlReader, \DOMNode $domNode) + private function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode) { $style = null; if ($xmlReader->elementExists('w:pPr', $domNode)) { @@ -620,6 +738,7 @@ class Word2007 extends AbstractReader implements ReaderInterface } $property = $mapping[$node->nodeName]; switch ($node->nodeName) { + case 'w:ind': $style['indent'] = $xmlReader->getAttribute('w:left', $node); $style['hanging'] = $xmlReader->getAttribute('w:hanging', $node); @@ -660,7 +779,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return string|array|null */ - private function readFontStyle(XMLReader $xmlReader, \DOMNode $domNode) + private function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) { $style = null; // Hyperlink has an extra w:r child @@ -686,6 +805,7 @@ class Word2007 extends AbstractReader implements ReaderInterface } $property = $mapping[$node->nodeName]; switch ($node->nodeName) { + case 'w:rFonts': $style['name'] = $xmlReader->getAttribute('w:ascii', $node); $style['hint'] = $xmlReader->getAttribute('w:hint', $node); @@ -729,7 +849,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * @return string|array|null * @todo Capture w:tblStylePr w:type="firstRow" */ - private function readTableStyle(XMLReader $xmlReader, \DOMNode $domNode) + private function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) { $style = null; $margins = array('top', 'left', 'bottom', 'right'); @@ -752,6 +872,7 @@ class Word2007 extends AbstractReader implements ReaderInterface } // $property = $mapping[$node->nodeName]; switch ($node->nodeName) { + case 'w:tblCellMar': foreach ($margins as $side) { $ucfSide = ucfirst($side); @@ -779,7 +900,7 @@ class Word2007 extends AbstractReader implements ReaderInterface * * @return array|null */ - private function readCellStyle(XMLReader $xmlReader, \DOMNode $domNode) + private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) { $style = null; $mapping = array( diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index e5b5facc..17e8454d 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -70,7 +70,7 @@ class XMLReader * @param string $path * @return \DOMNodeList */ - public function getElements($path, \DOMNode $contextNode = null) + public function getElements($path, \DOMElement $contextNode = null) { if ($this->dom === null) { return array(); @@ -86,9 +86,9 @@ class XMLReader * Get element * * @param string $path - * @return \DOMNode|null + * @return \DOMElement|null */ - public function getElement($path, \DOMNode $contextNode) + public function getElement($path, \DOMElement $contextNode) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -105,7 +105,7 @@ class XMLReader * @param string $path * @return string|null */ - public function getAttribute($attribute, \DOMNode $contextNode, $path = null) + public function getAttribute($attribute, \DOMElement $contextNode, $path = null) { if (is_null($path)) { $return = $contextNode->getAttribute($attribute); @@ -127,7 +127,7 @@ class XMLReader * @param string $path * @return string|null */ - public function getValue($path, \DOMNode $contextNode) + public function getValue($path, \DOMElement $contextNode) { $elements = $this->getElements($path, $contextNode); if ($elements->length > 0) { @@ -143,7 +143,7 @@ class XMLReader * @param string $path * @return integer */ - public function countElements($path, \DOMNode $contextNode) + public function countElements($path, \DOMElement $contextNode) { $elements = $this->getElements($path, $contextNode); @@ -156,7 +156,7 @@ class XMLReader * @param string $path * @return boolean */ - public function elementExists($path, \DOMNode $contextNode) + public function elementExists($path, \DOMElement $contextNode) { return $this->getElements($path, $contextNode)->length > 0; } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 5afbb91b..eb01786c 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -12,6 +12,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\Numbering; /** * Style collection @@ -68,11 +69,7 @@ class Style */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - if (!array_key_exists($styleName, self::$styles)) { - $style = new Table($styleTable, $styleFirstRow); - - self::$styles[$styleName] = $style; - } + self::setStyleValues($styleName, null, new Table($styleTable, $styleFirstRow)); } /** @@ -84,12 +81,36 @@ class Style */ public static function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) { - $styleName = 'Heading_' . $titleCount; self::setStyleValues("Heading_{$titleCount}", $styleFont, new Font('title', $styleParagraph)); } + /** + * Add numbering style + * + * @param string $styleName + * @param array $styleValues + * @return Numbering + * @since 0.9.2 + */ + public static function addNumberingStyle($styleName, $styleValues) + { + self::setStyleValues($styleName, $styleValues, new Numbering()); + } + + /** + * Count styles + * + * @return integer + * @since 0.9.2 + */ + public static function countStyles() + { + return count(self::$styles); + } + /** * Reset styles + * @since 0.9.2 */ public static function resetStyles() { @@ -120,6 +141,7 @@ class Style * Get style by name * * @param string $styleName + * @return Paragraph|Font|Table|Numbering|null */ public static function getStyle($styleName) { @@ -131,24 +153,21 @@ class Style } /** - * Set style values + * Set style values and put it to static style collection * * @param string $styleName * @param array $styleValues - * @param mixed $styleObject + * @param Paragraph|Font|Table|Numbering $styleObject */ private static function setStyleValues($styleName, $styleValues, $styleObject) { if (!array_key_exists($styleName, self::$styles)) { if (is_array($styleValues)) { foreach ($styleValues as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } $styleObject->setStyleValue($key, $value); } } - + $styleObject->setIndex(self::countStyles() + 1); // One based index self::$styles[$styleName] = $styleObject; } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index c17ea6e2..e77c26a6 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -16,6 +16,37 @@ namespace PhpOffice\PhpWord\Style; */ abstract class AbstractStyle { + /** + * Index number in Style collection for named style + * + * This number starts from one and defined in Style::setStyleValues() + * + * @var integer|null + */ + protected $index; + + /** + * Get index number + * + * @return integer|null + */ + public function getIndex() + { + return $this->index; + } + + /** + * Set index number + * + * @param integer|null $value + */ + public function setIndex($value = null) + { + $this->index = $this->setIntVal($value, $this->index); + + return $this; + } + /** * Set style value template method * @@ -23,8 +54,7 @@ abstract class AbstractStyle * * @param string $key * @param string $value - * - * @todo Implement type check mechanism, e.g. boolean, integer, enum, defaults + * @return self */ public function setStyleValue($key, $value) { @@ -39,5 +69,88 @@ abstract class AbstractStyle if (method_exists($this, $method)) { $this->$method($value); } + + return $this; + } + + /** + * Set style by using associative array + * + * @param array $styles + * @return self + */ + public function setStyleByArray($styles = array()) + { + foreach ($styles as $key => $value) { + $this->setStyleValue($key, $value); + } + + return $this; + } + + /** + * Set boolean value + * + * @param mixed $value + * @param boolean|null $default + * @return boolean|null + */ + protected function setBoolVal($value, $default = null) + { + if (!is_bool($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set integer value + * + * @param mixed $value + * @param integer|null $default + * @return integer|null + */ + protected function setIntVal($value, $default = null) + { + $value = intval($value); + if (!is_int($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set float value + * + * @param mixed $value + * @param float|null $default + * @return float|null + */ + protected function setFloatVal($value, $default = null) + { + $value = floatval($value); + if (!is_float($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set enum value + * + * @param mixed $value + * @param array $enum + * @param mixed $default + */ + protected function setEnumVal($value, $enum, $default = null) + { + if (!in_array($value, $enum)) { + $value = $default; + } + + return $value; } } diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index ecc4274c..93a3bb07 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -9,46 +9,240 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Numbering; + /** * List item style + * + * Before version 0.9.2, numbering style is defined statically with $listType. + * After version 0.9.2, numbering style is defined by using Numbering and + * recorded by $numStyle. $listStyle is maintained for backward compatility */ class ListItem extends AbstractStyle { + const TYPE_SQUARE_FILLED = 1; + const TYPE_BULLET_FILLED = 3; // default + const TYPE_BULLET_EMPTY = 5; const TYPE_NUMBER = 7; const TYPE_NUMBER_NESTED = 8; const TYPE_ALPHANUM = 9; - const TYPE_BULLET_FILLED = 3; - const TYPE_BULLET_EMPTY = 5; - const TYPE_SQUARE_FILLED = 1; /** - * List Type + * Legacy list type + * + * @var integer */ private $listType; /** - * Create a new ListItem Style + * Numbering style name + * + * @var string + * @since 0.9.2 */ - public function __construct() - { - $this->listType = self::TYPE_BULLET_FILLED; - } + private $numStyle; /** - * Set List Type + * Numbering definition instance ID * - * @param int $pValue + * @var integer + * @since 0.9.2 */ - public function setListType($pValue = self::TYPE_BULLET_FILLED) + private $numId; + + /** + * Create new instance + * + * @param string $numStyle + */ + public function __construct($numStyle = null) { - $this->listType = $pValue; + if (!is_null($numStyle)) { + $this->setNumStyle($numStyle); + } else { + $this->setListType(); + } } /** * Get List Type + * + * @return integer */ public function getListType() { return $this->listType; } + + /** + * Set legacy list type for version < 0.9.2 + * + * @param integer $value + */ + public function setListType($value = self::TYPE_BULLET_FILLED) + { + $enum = array(self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED, + self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER, + self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM); + $this->listType = $this->setEnumVal($value, $enum, $this->listType); + $this->getListTypeStyle(); + } + + /** + * Get numbering style name + * + * @return integer + */ + public function getNumStyle() + { + return $this->numStyle; + } + + /** + * Set numbering style name + * + * @param string $value + */ + public function setNumStyle($value) + { + $this->numStyle = $value; + $numStyleObject = Style::getStyle($this->numStyle); + if (!is_null($numStyleObject)) { + $this->numId = $numStyleObject->getIndex(); + $numStyleObject->setNumId($this->numId); + } + } + + /** + * Get numbering Id + * + * @return integer + */ + public function getNumId() + { + return $this->numId; + } + + /** + * Get legacy numbering definition + * + * @param integer $listType + * @return array + * @since 0.9.2 + */ + private function getListTypeStyle() + { + // Check if legacy style already registered in global Style collection + $numStyle = "PHPWordList{$this->listType}"; + if (!is_null(Style::getStyle($numStyle))) { + $this->setNumStyle($numStyle); + return; + } + + // Property mapping for numbering level information + $properties = array('start', 'format', 'text', 'align', 'tabPos', 'left', 'hanging', 'font', 'hint'); + + // Legacy level information + $listTypeStyles = array( + self::TYPE_SQUARE_FILLED => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, , left, 720, 720, 360, Wingdings, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_BULLET_FILLED => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, , left, 720, 720, 360, Symbol, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_BULLET_EMPTY => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, o, left, 720, 720, 360, Courier New, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_NUMBER => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 720, 720, 360, , default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_NUMBER_NESTED => array( + 'type' => 'multilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 360, 360, 360, , ', + 1 => '1, decimal, %1.%2., left, 792, 792, 432, , ', + 2 => '1, decimal, %1.%2.%3., left, 1224, 1224, 504, , ', + 3 => '1, decimal, %1.%2.%3.%4., left, 1800, 1728, 648, , ', + 4 => '1, decimal, %1.%2.%3.%4.%5., left, 2520, 2232, 792, , ', + 5 => '1, decimal, %1.%2.%3.%4.%5.%6., left, 2880, 2736, 936, , ', + 6 => '1, decimal, %1.%2.%3.%4.%5.%6.%7., left, 3600, 3240, 1080, , ', + 7 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8., left, 3960, 3744, 1224, , ', + 8 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8.%9., left, 4680, 4320, 1440, , ', + ), + ), + self::TYPE_ALPHANUM => array( + 'type' => 'multilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 720, 720, 360, , ', + 1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ', + 2 => '1, lowerRoman, %3., right, 2160, 2160, 180, , ', + 3 => '1, decimal, %4., left, 2880, 2880, 360, , ', + 4 => '1, lowerLetter, %5., left, 3600, 3600, 360, , ', + 5 => '1, lowerRoman, %6., right, 4320, 4320, 180, , ', + 6 => '1, decimal, %7., left, 5040, 5040, 360, , ', + 7 => '1, lowerLetter, %8., left, 5760, 5760, 360, , ', + 8 => '1, lowerRoman, %9., right, 6480, 6480, 180, , ', + ), + ), + ); + + // Populate style and register to global Style register + $style = $listTypeStyles[$this->listType]; + foreach ($style['levels'] as $key => $value) { + $levelProperties = explode(', ', $value); + $level['level'] = $key; + for ($i = 0; $i < count($properties); $i++) { + $property = $properties[$i]; + $level[$property] = $levelProperties[$i]; + } + $style['levels'][$key] = $level; + } + Style::addNumberingStyle($numStyle, $style); + $this->setNumStyle($numStyle); + } } diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php new file mode 100644 index 00000000..ce935b98 --- /dev/null +++ b/src/PhpWord/Style/Numbering.php @@ -0,0 +1,123 @@ +numId; + } + + /** + * Set Id + * + * @param integer $value + * @return self + */ + public function setNumId($value) + { + $this->numId = $this->setIntVal($value, $this->numId); + return $this; + } + + /** + * Get multilevel type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set multilevel type + * + * @param string $value + * @return self + */ + public function setType($value) + { + $enum = array('singleLevel', 'multilevel', 'hybridMultilevel'); + $this->type = $this->setEnumVal($value, $enum, $this->type); + return $this; + } + + /** + * Get levels + * + * @return NumberingLevel[] + */ + public function getLevels() + { + return $this->levels; + } + + /** + * Set multilevel type + * + * @param array $values + * @return self + */ + public function setLevels($values) + { + if (is_array($values)) { + foreach ($values as $key => $value) { + $numberingLevel = new NumberingLevel(); + if (is_array($value)) { + $numberingLevel->setStyleByArray($value); + $numberingLevel->setLevel($key); + } + $this->levels[$key] = $numberingLevel; + } + } + + return $this; + } +} diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php new file mode 100644 index 00000000..77b63b40 --- /dev/null +++ b/src/PhpWord/Style/NumberingLevel.php @@ -0,0 +1,378 @@ +level; + } + + /** + * Set level + * + * @param integer $value + * @return self + */ + public function setLevel($value) + { + $this->level = $this->setIntVal($value, $this->level); + return $this; + } + + /** + * Get start + * + * @return integer + */ + public function getStart() + { + return $this->start; + } + + /** + * Set start + * + * @param integer $value + * @return self + */ + public function setStart($value) + { + $this->start = $this->setIntVal($value, $this->start); + return $this; + } + + /** + * Get format + * + * @return string + */ + public function getFormat() + { + return $this->format; + } + + /** + * Set format + * + * @param string $value + * @return self + */ + public function setFormat($value) + { + $enum = array('bullet', 'decimal', 'upperRoman', 'lowerRoman', 'upperLetter', 'lowerLetter'); + $this->format = $this->setEnumVal($value, $enum, $this->format); + return $this; + } + + /** + * Get start + * + * @return integer + */ + public function getRestart() + { + return $this->restart; + } + + /** + * Set start + * + * @param integer $value + * @return self + */ + public function setRestart($value) + { + $this->restart = $this->setIntVal($value, $this->restart); + return $this; + } + + /** + * Get suffix + * + * @return string + */ + public function getSuffix() + { + return $this->suffix; + } + + /** + * Set suffix + * + * @param string $value + * @return self + */ + public function setSuffix($value) + { + $enum = array('tab', 'space', 'nothing'); + $this->suffix = $this->setEnumVal($value, $enum, $this->suffix); + return $this; + } + + /** + * Get text + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Set text + * + * @param string $value + * @return self + */ + public function setText($value) + { + $this->text = $value; + return $this; + } + + /** + * Get align + * + * @return string + */ + public function getAlign() + { + return $this->align; + } + + /** + * Set align + * + * @param string $value + * @return self + */ + public function setAlign($value) + { + $enum = array('left', 'center', 'right', 'both'); + $this->align = $this->setEnumVal($value, $enum, $this->align); + return $this; + } + + /** + * Get left + * + * @return integer + */ + public function getLeft() + { + return $this->left; + } + + /** + * Set left + * + * @param integer $value + * @return self + */ + public function setLeft($value) + { + $this->left = $this->setIntVal($value, $this->left); + return $this; + } + + /** + * Get hanging + * + * @return integer + */ + public function getHanging() + { + return $this->hanging; + } + + /** + * Set hanging + * + * @param integer $value + * @return self + */ + public function setHanging($value) + { + $this->hanging = $this->setIntVal($value, $this->hanging); + return $this; + } + + /** + * Get tab + * + * @return integer + */ + public function getTabPos() + { + return $this->tabPos; + } + + /** + * Set tab + * + * @param integer $value + * @return self + */ + public function setTabPos($value) + { + $this->tabPos = $this->setIntVal($value, $this->tabPos); + return $this; + } + + /** + * Get font + * + * @return string + */ + public function getFont() + { + return $this->font; + } + + /** + * Set font + * + * @param string $value + * @return self + */ + public function setFont($value) + { + $this->font = $value; + return $this; + } + + /** + * Get hint + * + * @return string + */ + public function getHint() + { + return $this->hint; + } + + /** + * Set hint + * + * @param string $value + * @return self + */ + public function setHint($value) + { + $enum = array('default', 'eastAsia', 'cs'); + $this->hint = $this->setEnumVal($value, $enum, $this->hint); + return $this; + } +} diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index b0be592d..9f71d306 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -432,6 +432,6 @@ class Template */ public function deleteTemplateBlock($blockname, $replacement = '') { - $this->deleteBlock($blockname, $replacement); + $this->deleteBlock($blockname); } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index b44708a3..7b552905 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -9,17 +9,18 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Media; +use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; -use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\DocProps; use PhpOffice\PhpWord\Writer\Word2007\Document; use PhpOffice\PhpWord\Writer\Word2007\Footer; -use PhpOffice\PhpWord\Writer\Word2007\Notes; use PhpOffice\PhpWord\Writer\Word2007\Header; +use PhpOffice\PhpWord\Writer\Word2007\Notes; +use PhpOffice\PhpWord\Writer\Word2007\Numbering; +use PhpOffice\PhpWord\Writer\Word2007\Rels; use PhpOffice\PhpWord\Writer\Word2007\Styles; /** @@ -57,6 +58,7 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->writerParts['docprops'] = new DocProps(); $this->writerParts['document'] = new Document(); $this->writerParts['styles'] = new Styles(); + $this->writerParts['numbering'] = new Numbering(); $this->writerParts['header'] = new Header(); $this->writerParts['footer'] = new Footer(); $this->writerParts['footnotes'] = new Notes(); @@ -97,7 +99,6 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->addHeaderFooterMedia($objZip, 'footer'); // Add header/footer contents - $overrides = array(); $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements $sections = $this->phpWord->getSections(); foreach ($sections as $section) { @@ -116,9 +117,9 @@ class Word2007 extends AbstractWriter implements WriterInterface $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($this->docRels)); $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord)); $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); + $objZip->addFromString('word/numbering.xml', $this->getWriterPart('numbering')->writeNumbering()); // Write static files - $objZip->addFile(__DIR__ . '/../_staticDocParts/numbering.xml', 'word/numbering.xml'); $objZip->addFile(__DIR__ . '/../_staticDocParts/settings.xml', 'word/settings.xml'); $objZip->addFile(__DIR__ . '/../_staticDocParts/theme1.xml', 'word/theme/theme1.xml'); $objZip->addFile(__DIR__ . '/../_staticDocParts/webSettings.xml', 'word/webSettings.xml'); @@ -224,8 +225,8 @@ class Word2007 extends AbstractWriter implements WriterInterface * Add footnotes/endnotes * * @param mixed $objZip - * @param string $elmType * @param integer $rId + * @param string $notesType */ private function addNotes($objZip, &$rId, $notesType = 'footnote') { diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php index 4fd38b57..b74211a5 100644 --- a/src/PhpWord/Writer/Word2007/Base.php +++ b/src/PhpWord/Writer/Word2007/Base.php @@ -279,7 +279,7 @@ class Base extends AbstractWriterPart { $textObject = $listItem->getTextObject(); $depth = $listItem->getDepth(); - $listType = $listItem->getStyle()->getListType(); + $numId = $listItem->getStyle()->getNumId(); $styleParagraph = $textObject->getParagraphStyle(); $xmlWriter->startElement('w:p'); @@ -290,7 +290,7 @@ class Base extends AbstractWriterPart $xmlWriter->writeAttribute('w:val', $depth); $xmlWriter->endElement(); // w:ilvl $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $listType); + $xmlWriter->writeAttribute('w:val', $numId); $xmlWriter->endElement(); // w:numId $xmlWriter->endElement(); // w:numPr $xmlWriter->endElement(); // w:pPr diff --git a/src/PhpWord/Writer/Word2007/Notes.php b/src/PhpWord/Writer/Word2007/Notes.php index 96393b4c..3b70ee74 100644 --- a/src/PhpWord/Writer/Word2007/Notes.php +++ b/src/PhpWord/Writer/Word2007/Notes.php @@ -69,7 +69,7 @@ class Notes extends Base // Content foreach ($elements as $element) { if ($element instanceof Footnote || $element instanceof Endnote) { - $this->writeNote($xmlWriter, $element, null, $notesTypes); + $this->writeNote($xmlWriter, $element, $notesTypes); } } @@ -83,10 +83,9 @@ class Notes extends Base * * @param XMLWriter $xmlWriter * @param Footnote|Endnote $element - * @param boolean $withoutP * @param string $notesTypes */ - protected function writeNote(XMLWriter $xmlWriter, $element, $withoutP = false, $notesTypes = 'footnotes') + protected function writeNote(XMLWriter $xmlWriter, $element, $notesTypes = 'footnotes') { $isFootnote = ($notesTypes == 'footnotes'); $elementNode = $isFootnote ? 'w:footnote' : 'w:endnote'; diff --git a/src/PhpWord/Writer/Word2007/Numbering.php b/src/PhpWord/Writer/Word2007/Numbering.php new file mode 100644 index 00000000..da127891 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Numbering.php @@ -0,0 +1,177 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:numbering'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + // Abstract numbering definitions + foreach ($styles as $style) { + if ($style instanceof NumberingStyle) { + $levels = $style->getLevels(); + + $xmlWriter->startElement('w:abstractNum'); + $xmlWriter->writeAttribute('w:abstractNumId', $style->getNumId()); + + $xmlWriter->startElement('w:nsid'); + $xmlWriter->writeAttribute('w:val', $this->getRandomHexNumber()); + $xmlWriter->endElement(); // w:nsid + + $xmlWriter->startElement('w:multiLevelType'); + $xmlWriter->writeAttribute('w:val', $style->getType()); + $xmlWriter->endElement(); // w:multiLevelType + + if (is_array($levels)) { + foreach ($levels as $levelNum => $levelObject) { + if ($levelObject instanceof NumberingLevel) { + $start = $levelObject->getStart(); + $format = $levelObject->getFormat(); + $restart = $levelObject->getRestart(); + $suffix = $levelObject->getSuffix(); + $text = $levelObject->getText(); + $align = $levelObject->getAlign(); + $tabPos = $levelObject->getTabPos(); + $left = $levelObject->getLeft(); + $hanging = $levelObject->getHanging(); + $font = $levelObject->getFont(); + $hint = $levelObject->getHint(); + + $xmlWriter->startElement('w:lvl'); + $xmlWriter->writeAttribute('w:ilvl', $levelNum); + + if (!is_null($start)) { + $xmlWriter->startElement('w:start'); + $xmlWriter->writeAttribute('w:val', $start); + $xmlWriter->endElement(); // w:start + } + if (!is_null($format)) { + $xmlWriter->startElement('w:numFmt'); + $xmlWriter->writeAttribute('w:val', $format); + $xmlWriter->endElement(); // w:numFmt + } + if (!is_null($restart)) { + $xmlWriter->startElement('w:lvlRestart'); + $xmlWriter->writeAttribute('w:val', $restart); + $xmlWriter->endElement(); // w:lvlRestart + } + if (!is_null($suffix)) { + $xmlWriter->startElement('w:suff'); + $xmlWriter->writeAttribute('w:val', $suffix); + $xmlWriter->endElement(); // w:suff + } + if (!is_null($text)) { + $xmlWriter->startElement('w:lvlText'); + $xmlWriter->writeAttribute('w:val', $text); + $xmlWriter->endElement(); // w:start + } + if (!is_null($align)) { + $xmlWriter->startElement('w:lvlJc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); // w:lvlJc + } + if (!is_null($tabPos) || !is_null($left) || !is_null($hanging)) { + $xmlWriter->startElement('w:pPr'); + if (!is_null($tabPos)) { + $xmlWriter->startElement('w:tabs'); + $xmlWriter->startElement('w:tab'); + $xmlWriter->writeAttribute('w:val', 'num'); + $xmlWriter->writeAttribute('w:pos', $tabPos); + $xmlWriter->endElement(); // w:tab + $xmlWriter->endElement(); // w:tabs + } + if (!is_null($left) || !is_null($hanging)) { + $xmlWriter->startElement('w:ind'); + if (!is_null($left)) { + $xmlWriter->writeAttribute('w:left', $left); + } + if (!is_null($hanging)) { + $xmlWriter->writeAttribute('w:hanging', $hanging); + } + $xmlWriter->endElement(); // w:ind + } + $xmlWriter->endElement(); // w:pPr + } + if (!is_null($font) || !is_null($hint)) { + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rFonts'); + if (!is_null($font)) { + $xmlWriter->writeAttribute('w:ascii', $font); + $xmlWriter->writeAttribute('w:hAnsi', $font); + $xmlWriter->writeAttribute('w:cs', $font); + } + if (!is_null($hint)) { + $xmlWriter->writeAttribute('w:hint', $hint); + } + $xmlWriter->endElement(); // w:rFonts + $xmlWriter->endElement(); // w:rPr + } + $xmlWriter->endElement(); // w:lvl + } + } + } + $xmlWriter->endElement(); // w:abstractNum + } + } + + // Numbering definition instances + foreach ($styles as $style) { + if ($style instanceof NumberingStyle) { + $xmlWriter->startElement('w:num'); + $xmlWriter->writeAttribute('w:numId', $style->getNumId()); + $xmlWriter->startElement('w:abstractNumId'); + $xmlWriter->writeAttribute('w:val', $style->getNumId()); + $xmlWriter->endElement(); // w:abstractNumId + $xmlWriter->endElement(); // w:num + } + } + + $xmlWriter->endElement(); + + return $xmlWriter->getData(); + } + + /** + * Get random hexadecimal number value + * + * @param int $length + * @return string + */ + private function getRandomHexNumber($length = 8) + { + return strtoupper(substr(md5(rand()), 0, $length)); + } +} diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index f0305f7f..14a54b2d 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -15,9 +15,12 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\Numbering; /** * Word2007 styles part writer + * + * @todo Do something with the numbering style introduced in 0.9.2 */ class Styles extends Base { @@ -38,37 +41,32 @@ class Styles extends Base // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); $xmlWriter->startElement('w:styles'); - $xmlWriter->writeAttribute( - 'xmlns:r', - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' - ); - $xmlWriter->writeAttribute( - 'xmlns:w', - 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' - ); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + // Write default styles $styles = Style::getStyles(); $this->writeDefaultStyles($xmlWriter, $phpWord, $styles); - // Write other styles + + // Write styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { if ($styleName == 'Normal') { continue; } - if ($style instanceof Font) { + $styleClass = str_replace('PhpOffice\\PhpWord\\Style\\', '', get_class($style)); + // Font style + if ($style instanceof Font) { $paragraphStyle = $style->getParagraphStyle(); $styleType = $style->getStyleType(); - $type = ($styleType == 'title') ? 'paragraph' : 'character'; - if (!is_null($paragraphStyle)) { $type = 'paragraph'; } $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', $type); - if ($styleType == 'title') { $arrStyle = explode('_', $styleName); $styleId = 'Heading' . $arrStyle[1]; @@ -80,11 +78,9 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); } - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - if (!is_null($paragraphStyle)) { // Point parent style to Normal $xmlWriter->startElement('w:basedOn'); @@ -94,19 +90,17 @@ class Styles extends Base } $this->writeFontStyle($xmlWriter, $style); - $xmlWriter->endElement(); + // Paragraph style } elseif ($style instanceof Paragraph) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'paragraph'); $xmlWriter->writeAttribute('w:customStyle', '1'); $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - // Parent style $basedOn = $style->getBasedOn(); if (!is_null($basedOn)) { @@ -114,7 +108,6 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', $basedOn); $xmlWriter->endElement(); } - // Next paragraph style $next = $style->getNext(); if (!is_null($next)) { @@ -126,22 +119,20 @@ class Styles extends Base $this->writeParagraphStyle($xmlWriter, $style); $xmlWriter->endElement(); + // Table style } elseif ($style instanceof Table) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'table'); $xmlWriter->writeAttribute('w:customStyle', '1'); $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - $xmlWriter->startElement('w:uiPriority'); $xmlWriter->writeAttribute('w:val', '99'); $xmlWriter->endElement(); $this->writeTableStyle($xmlWriter, $style); - $xmlWriter->endElement(); // w:style } } @@ -149,7 +140,6 @@ class Styles extends Base $xmlWriter->endElement(); // w:styles - // Return return $xmlWriter->getData(); } diff --git a/src/PhpWord/_staticDocParts/numbering.xml b/src/PhpWord/_staticDocParts/numbering.xml deleted file mode 100644 index ac229f40..00000000 --- a/src/PhpWord/_staticDocParts/numbering.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php index 8cceecb3..fa11638e 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php @@ -99,12 +99,12 @@ class DocumentTest extends \PHPUnit_Framework_TestCase $objectSrc = __DIR__ . "/../../_files/documents/sheet.xls"; $phpWord = new PhpWord(); - $phpWord->addParagraphStyle('pStyle', array('align' => 'center')); - $phpWord->addFontStyle('fStyle', array('size' => '20')); - $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); + $phpWord->addParagraphStyle('pStyle', array('align' => 'center')); // Style #1 + $phpWord->addFontStyle('fStyle', array('size' => '20')); // Style #2 + $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); // Style #3 $fontStyle = new Font('text', array('align' => 'center')); $section = $phpWord->addSection(); - $section->addListItem('List Item', 0, null, null, 'pStyle'); + $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #4 $section->addObject($objectSrc, array('align' => 'center')); $section->addTOC($fontStyle); $section->addTitle('Title 1', 1); @@ -113,7 +113,7 @@ class DocumentTest extends \PHPUnit_Framework_TestCase // List item $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId'); - $this->assertEquals(3, $element->getAttribute('w:val')); + $this->assertEquals(4, $element->getAttribute('w:val')); // Object $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject'); From 297eeaadf0f7fd6f36db34c81cfc1b4e23fec5b1 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 17:59:48 +0700 Subject: [PATCH 081/146] Documentation for new ListItem feature --- docs/elements.rst | 38 ++++++++++++++++++++++++++ src/PhpWord/Reader/Word2007.php | 20 ++++++++++---- src/PhpWord/Style.php | 20 +++++++------- src/PhpWord/Style/ListItem.php | 6 ++-- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Template.php | 13 --------- src/PhpWord/Writer/Word2007/Styles.php | 2 -- 7 files changed, 66 insertions(+), 35 deletions(-) diff --git a/docs/elements.rst b/docs/elements.rst index 62ee007f..b6842b65 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -207,10 +207,14 @@ Lists To add a list item use the function ``addListItem``. +Basic usage: + .. code-block:: php $section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); +Parameters: + - ``$text`` Text that appears in the document. - ``$depth`` Depth of list item. - ``$fontStyle`` See "Font style" section. @@ -219,6 +223,40 @@ To add a list item use the function ``addListItem``. PHPWord\_Style\_ListItem. - ``$paragraphStyle`` See "Paragraph style" section. +Advanced usage: + +You can also create your own numbering style by changing the ``$listStyle`` parameter +with the name of your numbering style. + +.. code-block:: php + + $phpWord->addNumberingStyle( + 'multilevel', + array('type' => 'multilevel', 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) + ); + $section->addListItem('List Item I', 0, null, 'multilevel'); + $section->addListItem('List Item I.a', 1, null, 'multilevel'); + $section->addListItem('List Item I.b', 1, null, 'multilevel'); + $section->addListItem('List Item II', 0, null, 'multilevel'); + +Level styles: + +- ``start`` Starting value +- ``format`` Numbering format bullet|decimal|upperRoman|lowerRoman|upperLetter|lowerLetter +- ``restart`` Restart numbering level symbol +- ``suffix`` Content between numbering symbol and paragraph text tab|space|nothing +- ``text`` Numbering level text e.g. %1 for nonbullet or bullet character +- ``align`` Numbering symbol align left|center|right|both +- ``left`` See paragraph style +- ``hanging`` See paragraph style +- ``tabPos`` See paragraph style +- ``font`` Font name +- ``hint`` See font style + Tables ------ diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index e03d28a0..4ff84c3f 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -221,9 +221,11 @@ class Word2007 extends AbstractReader implements ReaderInterface // Section properties if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { $settingsNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); - $settings = $this->readSectionStyle($xmlReader, $settingsNode); - $section->setSettings($settings); - $this->readHeaderFooter($filename, $settings, $section); + if (!is_null($settingsNode)) { + $settings = $this->readSectionStyle($xmlReader, $settingsNode); + $section->setSettings($settings); + $this->readHeaderFooter($filename, $settings, $section); + } $section = $this->phpWord->addSection(); } break; @@ -268,7 +270,9 @@ class Word2007 extends AbstractReader implements ReaderInterface $pStyle = $this->readParagraphStyle($xmlReader, $node); $fStyle = $this->readFontStyle($xmlReader, $node); if (empty($fStyle)) { - $this->phpWord->addParagraphStyle($name, $pStyle); + if (is_array($pStyle)) { + $this->phpWord->addParagraphStyle($name, $pStyle); + } } else { $this->phpWord->addFontStyle($name, $fStyle, $pStyle); } @@ -634,8 +638,9 @@ class Word2007 extends AbstractReader implements ReaderInterface } elseif ($rowNode->nodeName == 'w:tc') { // Cell $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); $cellStyle = null; - if ($xmlReader->elementExists('w:tcPr', $rowNode)) { - $cellStyle = $this->readCellStyle($xmlReader, $xmlReader->getElement('w:tcPr', $rowNode)); + $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); + if (!is_null($cellStyleNode)) { + $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); } $cell = $row->addCell($cellWidth, $cellStyle); @@ -786,6 +791,9 @@ class Word2007 extends AbstractReader implements ReaderInterface if ($domNode->nodeName == 'w:hyperlink') { $domNode = $xmlReader->getElement('w:r', $domNode); } + if (is_null($domNode)) { + return $style; + } if ($xmlReader->elementExists('w:rPr', $domNode)) { if ($xmlReader->elementExists('w:rPr/w:rStyle', $domNode)) { $style = $xmlReader->getAttribute('w:val', $domNode, 'w:rPr/w:rStyle'); diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index eb01786c..084d7131 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -34,7 +34,7 @@ class Style */ public static function addParagraphStyle($styleName, $styles) { - self::setStyleValues($styleName, $styles, new Paragraph()); + self::setStyleValues($styleName, new Paragraph(), $styles); } /** @@ -46,7 +46,7 @@ class Style */ public static function addFontStyle($styleName, $styleFont, $styleParagraph = null) { - self::setStyleValues($styleName, $styleFont, new Font('text', $styleParagraph)); + self::setStyleValues($styleName, new Font('text', $styleParagraph), $styleFont); } /** @@ -57,7 +57,7 @@ class Style */ public static function addLinkStyle($styleName, $styles) { - self::setStyleValues($styleName, $styles, new Font('link')); + self::setStyleValues($styleName, new Font('link'), $styles); } /** @@ -65,11 +65,11 @@ class Style * * @param string $styleName * @param array $styleTable - * @param array $styleFirstRow + * @param array|null $styleFirstRow */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - self::setStyleValues($styleName, null, new Table($styleTable, $styleFirstRow)); + self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); } /** @@ -81,7 +81,7 @@ class Style */ public static function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) { - self::setStyleValues("Heading_{$titleCount}", $styleFont, new Font('title', $styleParagraph)); + self::setStyleValues("Heading_{$titleCount}", new Font('title', $styleParagraph), $styleFont); } /** @@ -94,7 +94,7 @@ class Style */ public static function addNumberingStyle($styleName, $styleValues) { - self::setStyleValues($styleName, $styleValues, new Numbering()); + self::setStyleValues($styleName, new Numbering(), $styleValues); } /** @@ -156,13 +156,13 @@ class Style * Set style values and put it to static style collection * * @param string $styleName - * @param array $styleValues * @param Paragraph|Font|Table|Numbering $styleObject + * @param array|null $styleValues */ - private static function setStyleValues($styleName, $styleValues, $styleObject) + private static function setStyleValues($styleName, $styleObject, $styleValues = null) { if (!array_key_exists($styleName, self::$styles)) { - if (is_array($styleValues)) { + if (!is_null($styleValues) && is_array($styleValues)) { foreach ($styleValues as $key => $value) { $styleObject->setStyleValue($key, $value); } diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 93a3bb07..f9e5e947 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -10,7 +10,6 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Style\Numbering; /** * List item style @@ -92,7 +91,7 @@ class ListItem extends AbstractStyle /** * Get numbering style name * - * @return integer + * @return string */ public function getNumStyle() { @@ -108,7 +107,7 @@ class ListItem extends AbstractStyle { $this->numStyle = $value; $numStyleObject = Style::getStyle($this->numStyle); - if (!is_null($numStyleObject)) { + if ($numStyleObject instanceof Numbering) { $this->numId = $numStyleObject->getIndex(); $numStyleObject->setNumId($this->numId); } @@ -234,6 +233,7 @@ class ListItem extends AbstractStyle // Populate style and register to global Style register $style = $listTypeStyles[$this->listType]; foreach ($style['levels'] as $key => $value) { + $level = array(); $levelProperties = explode(', ', $value); $level['level'] = $key; for ($i = 0; $i < count($properties); $i++) { diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 77b63b40..2979f0c2 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -115,7 +115,7 @@ class NumberingLevel extends AbstractStyle */ public function getLevel() { - return $level->level; + return $this->level; } /** diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 9f71d306..65ffd75f 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -421,17 +421,4 @@ class Template } return substr($this->documentXML, $startPosition, ($endPosition - $startPosition)); } - - /** - * Delete a block of text - * - * @param string $blockname - * @param string $replacement - * @deprecated - * @codeCoverageIgnore - */ - public function deleteTemplateBlock($blockname, $replacement = '') - { - $this->deleteBlock($blockname); - } } diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index 14a54b2d..ae784982 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -15,7 +15,6 @@ use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; -use PhpOffice\PhpWord\Style\Numbering; /** * Word2007 styles part writer @@ -54,7 +53,6 @@ class Styles extends Base if ($styleName == 'Normal') { continue; } - $styleClass = str_replace('PhpOffice\\PhpWord\\Style\\', '', get_class($style)); // Font style if ($style instanceof Font) { From 42167f88558bf03d14b33c0305d0872052fb6bcb Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 18:16:24 +0700 Subject: [PATCH 082/146] Fix documentation format and some type check --- docs/general.rst | 4 ++-- src/PhpWord/Reader/Word2007.php | 8 ++++++-- src/PhpWord/Style/AbstractStyle.php | 2 +- src/PhpWord/Style/ListItem.php | 3 --- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/general.rst b/docs/general.rst index c267d87d..40c8da7e 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -63,9 +63,9 @@ XML Writer compatibility ~~~~~~~~~~~~~~~~~~~~~~~~ This option sets -```XMLWriter::setIndent`` `__ +`XMLWriter::setIndent `__ and -```XMLWriter::setIndentString`` `__. +`XMLWriter::setIndentString `__. The default value of this option is ``true`` (compatible), which is `required for OpenOffice `__ to render OOXML document correctly. You can set this option to ``false`` diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 4ff84c3f..8df6c4ec 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -224,7 +224,9 @@ class Word2007 extends AbstractReader implements ReaderInterface if (!is_null($settingsNode)) { $settings = $this->readSectionStyle($xmlReader, $settingsNode); $section->setSettings($settings); - $this->readHeaderFooter($filename, $settings, $section); + if (!is_null($settings)) { + $this->readHeaderFooter($filename, $settings, $section); + } } $section = $this->phpWord->addSection(); } @@ -237,7 +239,9 @@ class Word2007 extends AbstractReader implements ReaderInterface case 'w:sectPr': // Last section $settings = $this->readSectionStyle($xmlReader, $node); $section->setSettings($settings); - $this->readHeaderFooter($filename, $settings, $section); + if (!is_null($settings)) { + $this->readHeaderFooter($filename, $settings, $section); + } break; } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index e77c26a6..11bfd8a4 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -107,7 +107,7 @@ abstract class AbstractStyle /** * Set integer value * - * @param mixed $value + * @param integer|null $value * @param integer|null $default * @return integer|null */ diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index f9e5e947..bb04d0e6 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -100,8 +100,6 @@ class ListItem extends AbstractStyle /** * Set numbering style name - * - * @param string $value */ public function setNumStyle($value) { @@ -126,7 +124,6 @@ class ListItem extends AbstractStyle /** * Get legacy numbering definition * - * @param integer $listType * @return array * @since 0.9.2 */ From ae652a63795ef0b273f9b6c1717bd3bb66971db2 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 19:04:53 +0700 Subject: [PATCH 083/146] Update upcoming version number to 0.10.0 as per #178 --- CHANGELOG.md | 4 ++-- src/PhpWord/Element/AbstractElement.php | 6 +++--- src/PhpWord/Element/Endnote.php | 2 +- src/PhpWord/Element/Footer.php | 4 ++-- src/PhpWord/Element/Footnote.php | 4 ++-- src/PhpWord/Element/Header.php | 2 +- src/PhpWord/Element/ListItem.php | 2 +- src/PhpWord/Element/Object.php | 4 ++-- src/PhpWord/Element/Section.php | 12 ++++++------ src/PhpWord/Endnotes.php | 2 +- src/PhpWord/Footnotes.php | 22 ++++++++++----------- src/PhpWord/Media.php | 26 ++++++++++++------------- src/PhpWord/PhpWord.php | 2 +- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Shared/XMLReader.php | 2 +- src/PhpWord/Shared/ZipArchive.php | 2 +- src/PhpWord/Style.php | 6 +++--- src/PhpWord/Style/AbstractStyle.php | 4 ++-- src/PhpWord/Style/ListItem.php | 12 ++++++------ src/PhpWord/Style/Numbering.php | 2 +- src/PhpWord/Style/NumberingLevel.php | 2 +- src/PhpWord/Writer/AbstractWriter.php | 2 +- src/PhpWord/Writer/ODText/Base.php | 2 +- src/PhpWord/Writer/Word2007/Rels.php | 2 +- src/PhpWord/Writer/Word2007/Styles.php | 2 +- 25 files changed, 66 insertions(+), 66 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f96b4a63..d00f16c7 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. -## 0.9.2 - Not yet released +## 0.10.0 - Not yet released This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. @@ -29,7 +29,7 @@ This release marked heavy refactorings on internal code structure with the creat - General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 - Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, and list - @ivanlanin - Endnote: Ability to add endnotes - @ivanlanin -- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 +- ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 ### Bugfixes diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 6562cb5b..b7a03934 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -34,7 +34,7 @@ use PhpOffice\PhpWord\Element\CheckBox; /** * Container abstract class * - * @since 0.9.2 + * @since 0.10.0 */ abstract class AbstractElement { @@ -563,7 +563,7 @@ abstract class AbstractElement * Create textrun element * * @param mixed $paragraphStyle - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createTextRun($paragraphStyle = null) @@ -575,7 +575,7 @@ abstract class AbstractElement * Create footnote element * * @param mixed $paragraphStyle - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createFootnote($paragraphStyle = null) diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 084119c2..bdcf8e76 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Endnote element * - * @since 0.9.2 + * @since 0.10.0 */ class Endnote extends Footnote { diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php index 6d441126..8db9c6eb 100755 --- a/src/PhpWord/Element/Footer.php +++ b/src/PhpWord/Element/Footer.php @@ -44,7 +44,7 @@ class Footer extends AbstractElement * Set type * * @param string $value - * @since 0.9.2 + * @since 0.10.0 */ public function setType($value = self::AUTO) { @@ -55,7 +55,7 @@ class Footer extends AbstractElement * Get type * * @return string - * @since 0.9.2 + * @since 0.10.0 */ public function getType() { diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php index 4dcc1fd4..8f1cf7bc 100644 --- a/src/PhpWord/Element/Footnote.php +++ b/src/PhpWord/Element/Footnote.php @@ -48,7 +48,7 @@ class Footnote extends AbstractElement * Get Footnote Reference ID * * @return int - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function getReferenceId() @@ -60,7 +60,7 @@ class Footnote extends AbstractElement * Set Footnote Reference ID * * @param int $rId - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function setReferenceId($rId) diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php index c14ed0e7..e4211d29 100755 --- a/src/PhpWord/Element/Header.php +++ b/src/PhpWord/Element/Header.php @@ -64,7 +64,7 @@ class Header extends AbstractElement * Set header type * * @param string $value - * @since 0.9.2 + * @since 0.10.0 */ public function setType($value = self::AUTO) { diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 39bd6b1b..bebf8b38 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -53,7 +53,7 @@ class ListItem extends AbstractElement $this->textObject = new Text($text, $fontStyle, $paragraphStyle); $this->depth = $depth; - // Version >= 0.9.2 will pass numbering style name. Older version will use old method + // Version >= 0.10.0 will pass numbering style name. Older version will use old method if (!is_null($listStyle) && is_string($listStyle)) { $this->style = new ListItemStyle($listStyle); } else { diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php index fc373fbc..81004872 100644 --- a/src/PhpWord/Element/Object.php +++ b/src/PhpWord/Element/Object.php @@ -101,7 +101,7 @@ class Object extends AbstractElement * Get Object ID * * @return int - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function getObjectId() @@ -113,7 +113,7 @@ class Object extends AbstractElement * Set Object ID * * @param int $objId - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function setObjectId($objId) diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 6abbbf98..82060e85 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -113,7 +113,7 @@ class Section extends AbstractElement * * @param string $type * @return Header - * @since 0.9.2 + * @since 0.10.0 */ public function addHeader($type = Header::AUTO) { @@ -125,7 +125,7 @@ class Section extends AbstractElement * * @param string $type * @return Footer - * @since 0.9.2 + * @since 0.10.0 */ public function addFooter($type = Header::AUTO) { @@ -177,7 +177,7 @@ class Section extends AbstractElement * @param boolean $header * @return Header|Footer * @throws Exception - * @since 0.9.2 + * @since 0.10.0 */ private function addHeaderFooter($type = Header::AUTO, $header = true) { @@ -201,7 +201,7 @@ class Section extends AbstractElement * Create header * * @return Header - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createHeader() @@ -213,7 +213,7 @@ class Section extends AbstractElement * Create footer * * @return Footer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createFooter() @@ -225,7 +225,7 @@ class Section extends AbstractElement * Get footer * * @return Footer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function getFooter() diff --git a/src/PhpWord/Endnotes.php b/src/PhpWord/Endnotes.php index 4a065b96..206814e8 100644 --- a/src/PhpWord/Endnotes.php +++ b/src/PhpWord/Endnotes.php @@ -14,7 +14,7 @@ use PhpOffice\PhpWord\Element\Endnote; /** * Endnote collection * - * @since 0.9.2 + * @since 0.10.0 */ class Endnotes { diff --git a/src/PhpWord/Footnotes.php b/src/PhpWord/Footnotes.php index 57cfdab8..5ff9e8d1 100644 --- a/src/PhpWord/Footnotes.php +++ b/src/PhpWord/Footnotes.php @@ -29,7 +29,7 @@ class Footnotes * * @param Footnote $element * @return integer Reference ID - * @since 0.9.2 + * @since 0.10.0 */ public static function addElement($element) { @@ -44,7 +44,7 @@ class Footnotes * * @param integer $index * @param Footnote $element - * @since 0.9.2 + * @since 0.10.0 */ public static function setElement($index, $element) { @@ -58,7 +58,7 @@ class Footnotes * * @param integer $index * @return Footnote - * @since 0.9.2 + * @since 0.10.0 */ public static function getElement($index) { @@ -73,7 +73,7 @@ class Footnotes * Get elements * * @return array - * @since 0.9.2 + * @since 0.10.0 */ public static function getElements() { @@ -84,7 +84,7 @@ class Footnotes * Get element count * * @return integer - * @since 0.9.2 + * @since 0.10.0 */ public static function countElements() { @@ -94,7 +94,7 @@ class Footnotes /** * Reset elements * - * @since 0.9.2 + * @since 0.10.0 */ public static function resetElements() { @@ -106,7 +106,7 @@ class Footnotes * * @param Footnote $element * @return integer Reference ID - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addFootnoteElement($element) @@ -118,7 +118,7 @@ class Footnotes * Get Footnote Elements * * @return array - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function getFootnoteElements() @@ -130,7 +130,7 @@ class Footnotes * Get Footnote Elements Count * * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function countFootnoteElements() @@ -143,7 +143,7 @@ class Footnotes * * @param string $linkSrc * @return integer Reference ID - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addFootnoteLinkElement($linkSrc) @@ -155,7 +155,7 @@ class Footnotes * Get Footnote Link Elements * * @return array - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function getFootnoteLinkElements() diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 74f046bf..66079fd7 100755 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -32,7 +32,7 @@ class Media * @param string $source * @param Image $image * @return integer - * @since 0.9.2 + * @since 0.10.0 */ public static function addElement($container, $mediaType, $source, Image $image = null) { @@ -97,7 +97,7 @@ class Media * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @return integer - * @since 0.9.2 + * @since 0.10.0 */ public static function countElements($container, $mediaType = null) { @@ -124,7 +124,7 @@ class Media * @param string $container section|headerx|footerx|footnote|endnote * @param string $mediaType image|object|link * @return array - * @since 0.9.2 + * @since 0.10.0 */ public static function getElements($container, $mediaType = null) { @@ -170,7 +170,7 @@ class Media * @param string $type * @param Image $image * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addSectionMediaElement($src, $type, Image $image = null) @@ -183,7 +183,7 @@ class Media * * @param string $linkSrc * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addSectionLinkElement($linkSrc) @@ -196,7 +196,7 @@ class Media * * @param string $key * @return array - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function getSectionMediaElements($key = null) @@ -209,7 +209,7 @@ class Media * * @param string $key * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function countSectionMediaElements($key = null) @@ -224,7 +224,7 @@ class Media * @param string $src * @param Image $image * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) @@ -237,7 +237,7 @@ class Media * * @param string $key * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function countHeaderMediaElements($key) @@ -249,7 +249,7 @@ class Media * Get Header Media Elements * * @return array - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function getHeaderMediaElements() @@ -264,7 +264,7 @@ class Media * @param string $src * @param Image $image * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) @@ -277,7 +277,7 @@ class Media * * @param string $key * @return integer - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function countFooterMediaElements($key) @@ -289,7 +289,7 @@ class Media * Get Footer Media Elements * * @return array - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public static function getFooterMediaElements() diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index 2764a3a1..73ba1cc3 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -256,7 +256,7 @@ class PhpWord * * @param array $settings * @return Section - * @deprecated 0.9.2 + * @deprecated 0.10.0 * @codeCoverageIgnore */ public function createSection($settings = null) diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 8df6c4ec..5901046c 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -18,7 +18,7 @@ use PhpOffice\PhpWord\Element\Section; /** * Reader for Word2007 * - * @since 0.9.2 + * @since 0.10.0 * @todo title, list, watermark, checkbox, toc * @todo Partly done: image, object */ diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 17e8454d..b7f5549e 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Settings; /** * XML Reader wrapper * - * @since 0.9.2 + * @since 0.10.0 */ class XMLReader { diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 60b7198c..d8519aca 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -22,7 +22,7 @@ require_once 'PCLZip/pclzip.lib.php'; /** * PCLZip wrapper * - * @since 0.9.2 + * @since 0.10.0 */ class ZipArchive { diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 084d7131..e0b5d439 100755 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -90,7 +90,7 @@ class Style * @param string $styleName * @param array $styleValues * @return Numbering - * @since 0.9.2 + * @since 0.10.0 */ public static function addNumberingStyle($styleName, $styleValues) { @@ -101,7 +101,7 @@ class Style * Count styles * * @return integer - * @since 0.9.2 + * @since 0.10.0 */ public static function countStyles() { @@ -110,7 +110,7 @@ class Style /** * Reset styles - * @since 0.9.2 + * @since 0.10.0 */ public static function resetStyles() { diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 11bfd8a4..2c88bdb2 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -12,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Abstract style class * - * @since 0.9.2 + * @since 0.10.0 */ abstract class AbstractStyle { @@ -58,7 +58,7 @@ abstract class AbstractStyle */ public function setStyleValue($key, $value) { - // Backward compability check for versions < 0.9.2 which use underscore + // Backward compability check for versions < 0.10.0 which use underscore // prefix for their private properties if (substr($key, 0, 1) == '_') { $key = substr($key, 1); diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index bb04d0e6..3c762920 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -14,8 +14,8 @@ use PhpOffice\PhpWord\Style; /** * List item style * - * Before version 0.9.2, numbering style is defined statically with $listType. - * After version 0.9.2, numbering style is defined by using Numbering and + * Before version 0.10.0, numbering style is defined statically with $listType. + * After version 0.10.0, numbering style is defined by using Numbering and * recorded by $numStyle. $listStyle is maintained for backward compatility */ class ListItem extends AbstractStyle @@ -38,7 +38,7 @@ class ListItem extends AbstractStyle * Numbering style name * * @var string - * @since 0.9.2 + * @since 0.10.0 */ private $numStyle; @@ -46,7 +46,7 @@ class ListItem extends AbstractStyle * Numbering definition instance ID * * @var integer - * @since 0.9.2 + * @since 0.10.0 */ private $numId; @@ -75,7 +75,7 @@ class ListItem extends AbstractStyle } /** - * Set legacy list type for version < 0.9.2 + * Set legacy list type for version < 0.10.0 * * @param integer $value */ @@ -125,7 +125,7 @@ class ListItem extends AbstractStyle * Get legacy numbering definition * * @return array - * @since 0.9.2 + * @since 0.10.0 */ private function getListTypeStyle() { diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php index ce935b98..8c2e4a69 100644 --- a/src/PhpWord/Style/Numbering.php +++ b/src/PhpWord/Style/Numbering.php @@ -17,7 +17,7 @@ use PhpOffice\PhpWord\Style\NumberingLevel; * @link http://www.schemacentral.com/sc/ooxml/e-w_numbering.html * @link http://www.schemacentral.com/sc/ooxml/e-w_abstractNum-1.html * @link http://www.schemacentral.com/sc/ooxml/e-w_num-1.html - * @since 0.9.2 + * @since 0.10.0 */ class Numbering extends AbstractStyle { diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 2979f0c2..dff7de22 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -13,7 +13,7 @@ namespace PhpOffice\PhpWord\Style; * Numbering level definition * * @link http://www.schemacentral.com/sc/ooxml/e-w_lvl-1.html - * @since 0.9.2 + * @since 0.10.0 */ class NumberingLevel extends AbstractStyle { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index faa13ea6..684a5d32 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -16,7 +16,7 @@ use PhpOffice\PhpWord\Settings; /** * Abstract writer class * - * @since 0.9.2 + * @since 0.10.0 */ abstract class AbstractWriter implements WriterInterface { diff --git a/src/PhpWord/Writer/ODText/Base.php b/src/PhpWord/Writer/ODText/Base.php index a1f0d315..24eab60c 100644 --- a/src/PhpWord/Writer/ODText/Base.php +++ b/src/PhpWord/Writer/ODText/Base.php @@ -17,7 +17,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODT base part writer * - * @since 0.9.2 + * @since 0.10.0 */ class Base extends AbstractWriterPart { diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php index c708eeaf..ab3198dd 100755 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ b/src/PhpWord/Writer/Word2007/Rels.php @@ -15,7 +15,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; /** * Word2007 relationship writer * - * @since 0.9.2 + * @since 0.10.0 */ class Rels extends AbstractWriterPart { diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Styles.php index ae784982..38217847 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Styles.php @@ -19,7 +19,7 @@ use PhpOffice\PhpWord\Style\Table; /** * Word2007 styles part writer * - * @todo Do something with the numbering style introduced in 0.9.2 + * @todo Do something with the numbering style introduced in 0.10.0 */ class Styles extends Base { From a3a9af51e5ed991e75825de38a77404a0559f58e Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 21:16:07 +0700 Subject: [PATCH 084/146] Additional unit tests and some code deduplication --- src/PhpWord/Element/Section.php | 3 -- src/PhpWord/Shared/String.php | 17 +++++++ src/PhpWord/Style/AbstractStyle.php | 16 +++--- src/PhpWord/Style/Cell.php | 6 +-- src/PhpWord/Style/Font.php | 2 - src/PhpWord/Style/Paragraph.php | 7 +-- src/PhpWord/Style/Row.php | 35 +++++-------- src/PhpWord/Style/Section.php | 6 +-- src/PhpWord/Style/TOC.php | 11 ----- src/PhpWord/Style/Table.php | 12 ++--- src/PhpWord/TOC.php | 6 --- .../Tests/Style/NumberingLevelTest.php | 49 +++++++++++++++++++ 12 files changed, 96 insertions(+), 74 deletions(-) create mode 100644 tests/PhpWord/Tests/Style/NumberingLevelTest.php diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php index 82060e85..9e5dbd0a 100644 --- a/src/PhpWord/Element/Section.php +++ b/src/PhpWord/Element/Section.php @@ -66,9 +66,6 @@ class Section extends AbstractElement if (is_null($value)) { continue; } - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } $this->settings->setSettingValue($key, $value); } } diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index e603f034..95f75f13 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -77,6 +77,23 @@ class String return $value; } + /** + * Return name without underscore for < 0.10.0 variable name compatibility + * + * @param string $value + * @return string + */ + public static function removeUnderscorePrefix($value) + { + if (!is_null($value)) { + if (substr($value, 0, 1) == '_') { + $value = substr($value, 1); + } + } + + return $value; + } + /** * Build control characters array */ diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 2c88bdb2..45ba17a7 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -9,6 +9,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\String; + /** * Abstract style class * @@ -50,7 +52,10 @@ abstract class AbstractStyle /** * Set style value template method * - * Some child classes have their own specific overrides + * Some child classes have their own specific overrides. + * Backward compability check for versions < 0.10.0 which use underscore + * prefix for their private properties. + * Check if the set method is exists. Throws an exception? * * @param string $key * @param string $value @@ -58,14 +63,7 @@ abstract class AbstractStyle */ public function setStyleValue($key, $value) { - // Backward compability check for versions < 0.10.0 which use underscore - // prefix for their private properties - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } - - // Check if the set method is exists. Throws an exception? - $method = 'set' . $key; + $method = 'set' . String::removeUnderscorePrefix($key); if (method_exists($this, $method)) { $this->$method($value); } diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index 2e1f9d79..64a7f35a 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -9,6 +9,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\String; + /** * Table cell style */ @@ -145,9 +147,7 @@ class Cell extends AbstractStyle */ public function setStyleValue($key, $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } + $key = String::removeUnderscorePrefix($key); if ($key == 'borderSize') { $this->setBorderSize($value); } elseif ($key == 'borderColor') { diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 2fef3a66..dd8ff02a 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -193,8 +193,6 @@ class Font extends AbstractStyle if ($key === 'line-height') { $this->setLineHeight($value); null; - } elseif (substr($key, 0, 1) == '_') { - $key = substr($key, 1); } $this->setStyleValue($key, $value); } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 8feb7924..57ad4405 100755 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -10,6 +10,7 @@ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Shared\String; /** * Paragraph style @@ -127,8 +128,6 @@ class Paragraph extends AbstractStyle foreach ($style as $key => $value) { if ($key === 'line-height') { null; - } elseif (substr($key, 0, 1) == '_') { - $key = substr($key, 1); } $this->setStyleValue($key, $value); } @@ -144,9 +143,7 @@ class Paragraph extends AbstractStyle */ public function setStyleValue($key, $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } + $key = String::removeUnderscorePrefix($key); if ($key == 'indent' || $key == 'hanging') { $value = $value * 720; } elseif ($key == 'spacing') { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index d4dc642f..698adea4 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -45,16 +45,12 @@ class Row extends AbstractStyle /** * Set tblHeader * - * @param boolean $pValue - * @return $this + * @param boolean $value + * @return self */ - public function setTblHeader($pValue = false) + public function setTblHeader($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->tblHeader = $pValue; - return $this; + $this->tblHeader = $this->setBoolVal($value, $this->tblHeader); } /** @@ -70,16 +66,12 @@ class Row extends AbstractStyle /** * Set cantSplit * - * @param boolean $pValue - * @return $this + * @param boolean $value + * @return self */ - public function setCantSplit($pValue = false) + public function setCantSplit($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->cantSplit = $pValue; - return $this; + $this->cantSplit = $this->setBoolVal($value, $this->cantSplit); } /** @@ -95,15 +87,12 @@ class Row extends AbstractStyle /** * Set exactHeight * - * @param bool $pValue - * @return $this + * @param bool $value + * @return self */ - public function setExactHeight($pValue = false) + public function setExactHeight($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->exactHeight = $pValue; + $this->exactHeight = $this->setBoolVal($value, $this->exactHeight); return $this; } diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php index 6005e3ca..717fdaf7 100644 --- a/src/PhpWord/Style/Section.php +++ b/src/PhpWord/Style/Section.php @@ -9,6 +9,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\String; + /** * Section settings */ @@ -217,9 +219,7 @@ class Section extends AbstractStyle */ public function setSettingValue($key, $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } + $key = String::removeUnderscorePrefix($key); if ($key == 'orientation' && $value == 'landscape') { $this->setLandscape(); } elseif ($key == 'orientation' && is_null($value)) { diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index f7a752a9..e8a781b0 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -110,15 +110,4 @@ class TOC extends AbstractStyle { $this->indent = $pValue; } - - /** - * Set style value - * - * @param string $key - * @param string $value - */ - public function setStyleValue($key, $value) - { - $this->$key = $value; - } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php index f7c98c36..000ecff7 100755 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -9,6 +9,8 @@ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Shared\String; + /** * Table style */ @@ -161,18 +163,12 @@ class Table extends AbstractStyle unset($this->firstRow->borderInsideHColor); unset($this->firstRow->borderInsideHSize); foreach ($styleFirstRow as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } $this->firstRow->setStyleValue($key, $value); } } if (!is_null($styleTable) && is_array($styleTable)) { foreach ($styleTable as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } $this->setStyleValue($key, $value); } } @@ -186,9 +182,7 @@ class Table extends AbstractStyle */ public function setStyleValue($key, $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } + $key = String::removeUnderscorePrefix($key); if ($key == 'borderSize') { $this->setBorderSize($value); } elseif ($key == 'borderColor') { diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index d84bf770..22c79634 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -82,9 +82,6 @@ class TOC if (!is_null($styleTOC) && is_array($styleTOC)) { foreach ($styleTOC as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } self::$TOCStyle->setStyleValue($key, $value); } } @@ -93,9 +90,6 @@ class TOC if (is_array($styleFont)) { self::$fontStyle = new Font(); foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) == '_') { - $key = substr($key, 1); - } self::$fontStyle->setStyleValue($key, $value); } } else { diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php new file mode 100644 index 00000000..f3e28a0e --- /dev/null +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -0,0 +1,49 @@ + 1, + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'align' => 'left', + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', + ); + foreach ($attributes as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertEquals($value, $object->$get()); + } + } +} From a5c815d50cb4ba6caa23b49b91b2dc6fec23fab8 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Fri, 11 Apr 2014 23:02:05 +0700 Subject: [PATCH 085/146] ODT: Basic table writing support --- CHANGELOG.md | 1 + src/PhpWord/Element/AbstractElement.php | 100 ++++- src/PhpWord/Element/Table.php | 33 +- src/PhpWord/Writer/ODText/Content.php | 469 +++++++++++++++--------- 4 files changed, 412 insertions(+), 191 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d00f16c7..03400d46 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ This release marked heavy refactorings on internal code structure with the creat - Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, and list - @ivanlanin - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 +- ODT Writer: Basic table writing support - @ivanlanin ### Bugfixes diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index b7a03934..890227dc 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -81,6 +81,20 @@ abstract class AbstractElement */ protected $elements = array(); + /** + * Index of element in the elements collection (start with 1) + * + * @var integer + */ + protected $elementIndex = 1; + + /** + * Unique Id for element + * + * @var integer + */ + protected $elementId; + /** * Relation Id * @@ -108,7 +122,7 @@ abstract class AbstractElement $text = String::toUTF8($text); $textObject = new Text($text, $fontStyle, $paragraphStyle); $textObject->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $textObject; + $this->addElement($textObject); return $textObject; } @@ -125,7 +139,7 @@ abstract class AbstractElement $textRun = new TextRun($paragraphStyle); $textRun->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $textRun; + $this->addElement($textRun); return $textRun; } @@ -148,7 +162,7 @@ abstract class AbstractElement $link->setDocPart($this->getDocPart(), $this->getDocPartId()); $rId = Media::addElement($elementDocPart, 'link', $linkSrc); $link->setRelationId($rId); - $this->elements[] = $link; + $this->addElement($link); return $link; } @@ -179,7 +193,7 @@ abstract class AbstractElement $bookmarkId = $data[1]; $title->setAnchor($anchor); $title->setBookmarkId($bookmarkId); - $this->elements[] = $title; + $this->addElement($title); return $title; } @@ -198,7 +212,7 @@ abstract class AbstractElement $preserveText = new PreserveText(String::toUTF8($text), $fontStyle, $paragraphStyle); $preserveText->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $preserveText; + $this->addElement($preserveText); return $preserveText; } @@ -217,7 +231,7 @@ abstract class AbstractElement for ($i = 1; $i <= $count; $i++) { $textBreak = new TextBreak($fontStyle, $paragraphStyle); $textBreak->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $textBreak; + $this->addElement($textBreak); } } @@ -237,7 +251,7 @@ abstract class AbstractElement $listItem = new ListItem(String::toUTF8($text), $depth, $fontStyle, $styleList, $paragraphStyle); $listItem->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $listItem; + $this->addElement($listItem); return $listItem; } @@ -253,7 +267,7 @@ abstract class AbstractElement $this->checkValidity('table'); $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); - $this->elements[] = $table; + $this->addElement($table); return $table; } @@ -275,7 +289,8 @@ abstract class AbstractElement $image->setDocPart($this->getDocPart(), $this->getDocPartId()); $rId = Media::addElement($elementDocPart, 'image', $src, $image); $image->setRelationId($rId); - $this->elements[] = $image; + $this->addElement($image); + return $image; } @@ -307,7 +322,8 @@ abstract class AbstractElement $object->setRelationId($rId); $rIdimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); $object->setImageRelationId($rIdimg); - $this->elements[] = $object; + $this->addElement($object); + return $object; } else { throw new InvalidObjectException(); @@ -329,7 +345,7 @@ abstract class AbstractElement $footnote->setDocPart('footnote', $this->getDocPartId()); $footnote->setRelationId($rId); - $this->elements[] = $footnote; + $this->addElement($footnote); return $footnote; } @@ -349,7 +365,7 @@ abstract class AbstractElement $endnote->setDocPart('endnote', $this->getDocPartId()); $endnote->setRelationId($rId); - $this->elements[] = $endnote; + $this->addElement($endnote); return $endnote; } @@ -369,7 +385,7 @@ abstract class AbstractElement $checkBox = new CheckBox(String::toUTF8($name), String::toUTF8($text), $fontStyle, $paragraphStyle); $checkBox->setDocPart($this->getDocPart(), $this->getDocPartId()); - $this->elements[] = $checkBox; + $this->addElement($checkBox); return $checkBox; } @@ -416,6 +432,16 @@ abstract class AbstractElement return $this->docPartId; } + /** + * Set element index and unique id, and add element into elements collection + */ + protected function addElement(AbstractElement $element) + { + $element->setElementIndex($this->countElements() + 1); + $element->setElementId(); + $this->elements[] = $element; + } + /** * Get all elements * @@ -426,6 +452,54 @@ abstract class AbstractElement return $this->elements; } + /** + * Count elements + * + * @return integer + */ + public function countElements() + { + return count($this->elements); + } + + /** + * Get element index + * + * @return int + */ + public function getElementIndex() + { + return $this->elementIndex; + } + + /** + * Set element index + * + * @param int $value + */ + public function setElementIndex($value) + { + $this->elementIndex = $value; + } + + /** + * Get element unique ID + * + * @return string + */ + public function getElementId() + { + return $this->elementId; + } + + /** + * Set element unique ID from 6 first digit of md5 + */ + public function setElementId() + { + $this->elementId = substr(md5(rand()), 0, 6); + } + /** * Get relation Id * diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 90913582..3241a8e2 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -35,7 +35,7 @@ class Table extends AbstractElement /** * Table width * - * @var int + * @var integer */ private $width = null; @@ -44,7 +44,7 @@ class Table extends AbstractElement * Create a new table * * @param string $docPart - * @param int $docPartId + * @param integer $docPartId * @param mixed $style */ public function __construct($docPart, $docPartId, $style = null) @@ -56,7 +56,7 @@ class Table extends AbstractElement /** * Add a row * - * @param int $height + * @param integer $height * @param mixed $style */ public function addRow($height = null, $style = null) @@ -69,7 +69,7 @@ class Table extends AbstractElement /** * Add a cell * - * @param int $width + * @param integer $width * @param mixed $style * @return Cell */ @@ -103,7 +103,7 @@ class Table extends AbstractElement /** * Set table width * - * @param int $width + * @param integer $width */ public function setWidth($width) { @@ -113,10 +113,31 @@ class Table extends AbstractElement /** * Get table width * - * @return int + * @return integer */ public function getWidth() { return $this->width; } + + /** + * Get column count + * + * @return integer + */ + public function countColumns() + { + $columnCount = 0; + if (is_array($this->rows)) { + $rowCount = count($this->rows); + for ($i = 0; $i < $rowCount; $i++) { + $cellCount = count($this->rows[$i]->getCells()); + if ($columnCount < $cellCount) { + $columnCount = $cellCount; + } + } + } + + return $columnCount; + } } diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index 327aed34..e8f087fe 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -24,7 +24,6 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\TOC; /** * ODText content part writer @@ -34,7 +33,6 @@ class Content extends Base /** * Write content file to XML format * - * @param PhpWord $phpWord * @return string XML Output */ public function writeContent(PhpWord $phpWord = null) @@ -95,10 +93,304 @@ class Content extends Base } } - // office:font-face-decls - $this->writeFontFaces($xmlWriter); - // office:automatic-styles + $this->writeFontFaces($xmlWriter); // office:font-face-decls + + $this->writeAutomaticStyles($xmlWriter); // office:automatic-styles + + // Tables + $sections = $phpWord->getSections(); + $countSections = count($sections); + if ($countSections > 0) { + $sectionId = 0; + foreach ($sections as $section) { + $sectionId++; + $elements = $section->getElements(); + foreach ($elements as $element) { + if ($elements instanceof Table) { + $objWriter->startElement('style:style'); + $objWriter->writeAttribute('style:name', $element->getElementId()); + $objWriter->writeAttribute('style:family', 'table'); + $objWriter->startElement('style:table-properties'); + //$objWriter->writeAttribute('style:width', 'table'); + $objWriter->writeAttribute('style:rel-width', 100); + $objWriter->writeAttribute('table:align', 'center'); + $objWriter->endElement(); + $objWriter->endElement(); + } + } + } + } + + $xmlWriter->endElement(); + + // office:body + $xmlWriter->startElement('office:body'); + // office:text + $xmlWriter->startElement('office:text'); + // text:sequence-decls + $xmlWriter->startElement('text:sequence-decls'); + // text:sequence-decl + $xmlWriter->startElement('text:sequence-decl'); + $xmlWriter->writeAttribute('text:display-outline-level', 0); + $xmlWriter->writeAttribute('text:name', 'Illustration'); + $xmlWriter->endElement(); + // text:sequence-decl + $xmlWriter->startElement('text:sequence-decl'); + $xmlWriter->writeAttribute('text:display-outline-level', 0); + $xmlWriter->writeAttribute('text:name', 'Table'); + $xmlWriter->endElement(); + // text:sequence-decl + $xmlWriter->startElement('text:sequence-decl'); + $xmlWriter->writeAttribute('text:display-outline-level', 0); + $xmlWriter->writeAttribute('text:name', 'Text'); + $xmlWriter->endElement(); + // text:sequence-decl + $xmlWriter->startElement('text:sequence-decl'); + $xmlWriter->writeAttribute('text:display-outline-level', 0); + $xmlWriter->writeAttribute('text:name', 'Drawing'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $sections = $phpWord->getSections(); + $countSections = count($sections); + if ($countSections > 0) { + foreach ($sections as $section) { + $elements = $section->getElements(); + + foreach ($elements as $element) { + if ($element instanceof Text) { + $this->writeText($xmlWriter, $element); + } elseif ($element instanceof TextRun) { + $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof Link) { + $this->writeLink($xmlWriter, $element); + } elseif ($element instanceof Title) { + $this->writeTitle($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); + } elseif ($element instanceof TextBreak) { + $this->writeTextBreak($xmlWriter); + } elseif ($element instanceof PageBreak) { + $this->writePageBreak($xmlWriter); + } elseif ($element instanceof Table) { + $this->writeTable($xmlWriter, $element); + } elseif ($element instanceof Image) { + $this->writeImage($xmlWriter, $element); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element); + } + } + } + } + $xmlWriter->endElement(); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + // Return + return $xmlWriter->getData(); + } + + /** + * Write text + * + * @param bool $withoutP + */ + protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) + { + $styleFont = $text->getFontStyle(); + $styleParagraph = $text->getParagraphStyle(); + + // @todo Commented for TextRun. Should really checkout this value + // $SfIsObject = ($styleFont instanceof Font) ? true : false; + $SfIsObject = false; + + if ($SfIsObject) { + // Don't never be the case, because I browse all sections for cleaning all styles not declared + die('PhpWord : $SfIsObject wouldn\'t be an object'); + } else { + if (!$withoutP) { + $xmlWriter->startElement('text:p'); // text:p + } + if (empty($styleFont)) { + if (empty($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', 'P1'); + } elseif (is_string($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', $styleParagraph); + } + $xmlWriter->writeRaw($text->getText()); + } else { + if (empty($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', 'Standard'); + } elseif (is_string($styleParagraph)) { + $xmlWriter->writeAttribute('text:style-name', $styleParagraph); + } + // text:span + $xmlWriter->startElement('text:span'); + if (is_string($styleFont)) { + $xmlWriter->writeAttribute('text:style-name', $styleFont); + } + $xmlWriter->writeRaw($text->getText()); + $xmlWriter->endElement(); + } + if (!$withoutP) { + $xmlWriter->endElement(); // text:p + } + } + } + + /** + * Write TextRun section + * + * @todo Enable all other section types + */ + protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) + { + $elements = $textrun->getElements(); + $xmlWriter->startElement('text:p'); + if (count($elements) > 0) { + foreach ($elements as $element) { + if ($element instanceof Text) { + $this->writeText($xmlWriter, $element, true); + } + } + } + $xmlWriter->endElement(); + } + + /** + * Write link element + */ + protected function writeLink(XMLWriter $xmlWriter, Link $link) + { + $this->writeUnsupportedElement($xmlWriter, 'Link'); + } + + /** + * Write title element + */ + protected function writeTitle(XMLWriter $xmlWriter, Title $title) + { + $this->writeUnsupportedElement($xmlWriter, 'Title'); + } + + /** + * Write preserve text + */ + protected function writePreserveText(XMLWriter $xmlWriter, PreserveText $preservetext) + { + $this->writeUnsupportedElement($xmlWriter, 'PreserveText'); + } + + /** + * Write list item + */ + protected function writeListItem(XMLWriter $xmlWriter, ListItem $listItem) + { + $this->writeUnsupportedElement($xmlWriter, 'ListItem'); + } + + /** + * Write text break + */ + protected function writeTextBreak(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'Standard'); + $xmlWriter->endElement(); + } + + /** + * Write page break + */ + protected function writePageBreak(XMLWriter $xmlWriter) + { + $this->writeUnsupportedElement($xmlWriter, 'PageBreak'); + } + + /** + * Write table + */ + protected function writeTable(XMLWriter $xmlWriter, Table $table) + { + $rows = $table->getRows(); + $rowCount = count($rows); + $colCount = $table->countColumns(); + if ($rowCount > 0) { + $xmlWriter->startElement('table:table'); + $xmlWriter->writeAttribute('table:name', $table->getElementId()); + $xmlWriter->writeAttribute('table:style', $table->getElementId()); + + $xmlWriter->startElement('table:table-column'); + $xmlWriter->writeAttribute('table:number-columns-repeated', $colCount); + $xmlWriter->endElement(); // table:table-column + + foreach ($rows as $row) { + $xmlWriter->startElement('table:table-row'); + foreach ($row->getCells() as $cell) { + $xmlWriter->startElement('table:table-cell'); + $xmlWriter->writeAttribute('office:value-type', 'string'); + $elements = $cell->getElements(); + if (count($elements) > 0) { + foreach ($elements as $element) { + if ($element instanceof Text) { + $this->writeText($xmlWriter, $element); + } elseif ($element instanceof TextRun) { + $this->writeTextRun($xmlWriter, $element); + } elseif ($element instanceof ListItem) { + $this->writeListItem($xmlWriter, $element); + } elseif ($element instanceof TextBreak) { + $this->writeTextBreak($xmlWriter); + } elseif ($element instanceof Image) { + $this->writeImage($xmlWriter, $element); + } elseif ($element instanceof Object) { + $this->writeObject($xmlWriter, $element); + } + } + } else { + $this->writeTextBreak($xmlWriter); + } + $xmlWriter->endElement(); // table:table-cell + } + $xmlWriter->endElement(); // table:table-row + } + $xmlWriter->endElement(); // table:table + } + } + + /** + * Write image + */ + protected function writeImage(XMLWriter $xmlWriter, Image $element) + { + $this->writeUnsupportedElement($xmlWriter, 'Image'); + } + + /** + * Write object + */ + protected function writeObject(XMLWriter $xmlWriter, Object $element) + { + $this->writeUnsupportedElement($xmlWriter, 'Object'); + } + + /** + * Write unsupported element + * + * @param string $element + */ + private function writeUnsupportedElement(XMLWriter $xmlWriter, $element) + { + $xmlWriter->startElement('text:p'); + $xmlWriter->writeRaw($element); + $xmlWriter->endElement(); + } + + /** + * Write automatic styles + */ + private function writeAutomaticStyles(XMLWriter $xmlWriter) + { $xmlWriter->startElement('office:automatic-styles'); $styles = Style::getStyles(); $numPStyles = 0; @@ -151,172 +443,5 @@ class Content extends Base $xmlWriter->endElement(); } } - $xmlWriter->endElement(); - - // office:body - $xmlWriter->startElement('office:body'); - // office:text - $xmlWriter->startElement('office:text'); - // text:sequence-decls - $xmlWriter->startElement('text:sequence-decls'); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Illustration'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Table'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Text'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Drawing'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $sections = $phpWord->getSections(); - $countSections = count($sections); - if ($countSections > 0) { - foreach ($sections as $section) { - $elements = $section->getElements(); - - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->writeTextRun($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->writeTextBreak($xmlWriter); - } elseif ($element instanceof Link) { - $this->writeUnsupportedElement($xmlWriter, 'Link'); - } elseif ($element instanceof Title) { - $this->writeUnsupportedElement($xmlWriter, 'Title'); - } elseif ($element instanceof PageBreak) { - $this->writeUnsupportedElement($xmlWriter, 'Page Break'); - } elseif ($element instanceof Table) { - $this->writeUnsupportedElement($xmlWriter, 'Table'); - } elseif ($element instanceof ListItem) { - $this->writeUnsupportedElement($xmlWriter, 'List Item'); - } elseif ($element instanceof Image) { - $this->writeUnsupportedElement($xmlWriter, 'Image'); - } elseif ($element instanceof Object) { - $this->writeUnsupportedElement($xmlWriter, 'Object'); - } elseif ($element instanceof TOC) { - $this->writeUnsupportedElement($xmlWriter, 'TOC'); - } else { - $this->writeUnsupportedElement($xmlWriter, 'Element'); - } - } - } - } - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Write text - * - * @param XMLWriter $xmlWriter - * @param Text $text - * @param bool $withoutP - */ - protected function writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) - { - $styleFont = $text->getFontStyle(); - $styleParagraph = $text->getParagraphStyle(); - - // @todo Commented for TextRun. Should really checkout this value - // $SfIsObject = ($styleFont instanceof Font) ? true : false; - $SfIsObject = false; - - if ($SfIsObject) { - // Don't never be the case, because I browse all sections for cleaning all styles not declared - die('PhpWord : $SfIsObject wouldn\'t be an object'); - } else { - if (!$withoutP) { - $xmlWriter->startElement('text:p'); // text:p - } - if (empty($styleFont)) { - if (empty($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); - } elseif (is_string($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', $styleParagraph); - } - $xmlWriter->writeRaw($text->getText()); - } else { - if (empty($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - } elseif (is_string($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', $styleParagraph); - } - // text:span - $xmlWriter->startElement('text:span'); - if (is_string($styleFont)) { - $xmlWriter->writeAttribute('text:style-name', $styleFont); - } - $xmlWriter->writeRaw($text->getText()); - $xmlWriter->endElement(); - } - if (!$withoutP) { - $xmlWriter->endElement(); // text:p - } - } - } - - /** - * Write TextRun section - * - * @param XMLWriter $xmlWriter - * @param TextRun $textrun - * @todo Enable all other section types - */ - protected function writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) - { - $elements = $textrun->getElements(); - $xmlWriter->startElement('text:p'); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->writeText($xmlWriter, $element, true); - } - } - } - $xmlWriter->endElement(); - } - - /** - * Write TextBreak - * - * @param XMLWriter $xmlWriter - */ - protected function writeTextBreak(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - $xmlWriter->endElement(); - } - - /** - * Write unsupported element - * - * @param XMLWriter $xmlWriter - * @param string $element - */ - private function writeUnsupportedElement($xmlWriter, $element) - { - $xmlWriter->startElement('text:p'); - $xmlWriter->writeRaw($element); - $xmlWriter->endElement(); } } From fb35a5f80cf3394d9774a934b851fc7c249bccf4 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 12 Apr 2014 00:40:22 +0700 Subject: [PATCH 086/146] Change object name --- src/PhpWord/Writer/ODText/Content.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php index e8f087fe..01af3053 100644 --- a/src/PhpWord/Writer/ODText/Content.php +++ b/src/PhpWord/Writer/ODText/Content.php @@ -108,15 +108,15 @@ class Content extends Base $elements = $section->getElements(); foreach ($elements as $element) { if ($elements instanceof Table) { - $objWriter->startElement('style:style'); - $objWriter->writeAttribute('style:name', $element->getElementId()); - $objWriter->writeAttribute('style:family', 'table'); - $objWriter->startElement('style:table-properties'); - //$objWriter->writeAttribute('style:width', 'table'); - $objWriter->writeAttribute('style:rel-width', 100); - $objWriter->writeAttribute('table:align', 'center'); - $objWriter->endElement(); - $objWriter->endElement(); + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $element->getElementId()); + $xmlWriter->writeAttribute('style:family', 'table'); + $xmlWriter->startElement('style:table-properties'); + //$xmlWriter->writeAttribute('style:width', 'table'); + $xmlWriter->writeAttribute('style:rel-width', 100); + $xmlWriter->writeAttribute('table:align', 'center'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); } } } From 59e623bb752b50a1f0399e5474e9bf84eafae399 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 12 Apr 2014 00:56:24 +0200 Subject: [PATCH 087/146] Fixes #195 : Update general.rst --- docs/general.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/general.rst b/docs/general.rst index 40c8da7e..c7e55d5a 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -108,7 +108,7 @@ name. Use the following functions: .. code-block:: php - $properties = $phpWord->getProperties(); + $properties = $phpWord->getDocumentProperties(); $properties->setCreator('My name'); $properties->setCompany('My factory'); $properties->setTitle('My title'); From b40218da4571c5c32e42fb22e5df79a7a9764ffa Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sat, 12 Apr 2014 00:59:29 +0200 Subject: [PATCH 088/146] Add some unit tests for Shared & Element (100%!) - @Progi1984 --- CHANGELOG.md | 2 ++ src/PhpWord/Shared/ZipArchive.php | 3 +- .../Tests/Element/AbstractElementTest.php | 30 ++++++++++++++++++ tests/PhpWord/Tests/Element/ImageTest.php | 15 +++++++++ tests/PhpWord/Tests/Element/TableTest.php | 22 ++++++++++--- tests/PhpWord/Tests/Shared/ZipArchiveTest.php | 31 +++++++++++++++++++ 6 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 tests/PhpWord/Tests/Element/AbstractElementTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 03400d46..6a932eda 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ This release marked heavy refactorings on internal code structure with the creat ### Bugfixes - Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 +- Documentation : Error in a fonction - @theBeerNut GH-195 ### Deprecated @@ -63,6 +64,7 @@ This release marked heavy refactorings on internal code structure with the creat - Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 - Writer: New 'ODText\Base` class - @ivanlanin GH-187 - General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin +- General: Add some unit tests for Shared & Element (100%!) - @Progi1984 ## 0.9.1 - 27 Mar 2014 diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index d8519aca..21d13cfe 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -218,8 +218,7 @@ class ZipArchive public function getNameIndex($index) { $list = $this->zip->listContent(); - $listCount = count($list); - if ($index <= $listCount) { + if (isset($list[$index])) { return $list[$index]['filename']; } else { return false; diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php new file mode 100644 index 00000000..786248d5 --- /dev/null +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -0,0 +1,30 @@ +getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $ival = rand(0, 100); + $stub->setElementIndex($ival); + $this->assertEquals($stub->getElementIndex(), $ival); + } + public function testElementId(){ + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $stub->setElementId(); + $this->assertEquals(strlen($stub->getElementId()), 6); + } +} diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 5b9aaa45..3520c376 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -94,6 +94,11 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } + public function testStyleWrappingStyle() + { + + } + /** * Get relation Id */ @@ -202,4 +207,14 @@ class ImageTest extends \PHPUnit_Framework_TestCase { $object = new Image('test.php'); } + + /** + * Test PCX Image and Memory + * + * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException + */ + public function testPcxImage() + { + $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); + } } diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php index 0d3a74b9..53ec54be 100644 --- a/tests/PhpWord/Tests/Element/TableTest.php +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -84,9 +84,23 @@ class TableTest extends \PHPUnit_Framework_TestCase */ public function testCell() { - $oTable = new Table('section', 1); - $oTable->addRow(); - $element = $oTable->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); + } + + /** + * Add cell + */ + public function testCountColumns() + { + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 1); + $element = $oTable->addCell(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 3); } } diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php index ba47ade1..5094d5a1 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -32,7 +32,38 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase $this->assertTrue($object->locateName('xls/new.xls')); $this->assertEquals('Test', $object->getFromName('content/string.txt')); + $this->assertEquals('Test', $object->getFromName('/content/string.txt')); unlink($zipFile); } + + public function testLocate() + { + $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $object = new ZipArchive(); + $object->open($zipFile); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); + + $this->assertEquals(1, $object->locateName('content/string.txt')); + $this->assertFalse($object->locateName('blablabla')); + + unlink($zipFile); + } + + public function testNameIndex() + { + $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $object = new ZipArchive(); + $object->open($zipFile); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); + + $this->assertFalse($object->getNameIndex(-1)); + $this->assertEquals('content/string.txt', $object->getNameIndex(1)); + + unlink($zipFile); + } } From 47956b019cb6d13bf9d78d7f1d7c7f0ad414d002 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 12 Apr 2014 10:23:31 +0700 Subject: [PATCH 089/146] Code formatting and some more tests --- src/PhpWord/Reader/Word2007.php | 2 +- src/PhpWord/Style/ListItem.php | 2 + .../Tests/Element/AbstractElementTest.php | 26 ++++++--- tests/PhpWord/Tests/Element/ImageTest.php | 5 +- tests/PhpWord/Tests/Element/TableTest.php | 36 ++++++------ tests/PhpWord/Tests/Shared/XMLReaderTest.php | 54 ++++++++++++++++++ tests/PhpWord/Tests/Shared/ZipArchiveTest.php | 46 ++++++++------- tests/PhpWord/Tests/Style/ImageTest.php | 4 +- .../Tests/_files/documents/reader.docx | Bin 69796 -> 74101 bytes 9 files changed, 124 insertions(+), 51 deletions(-) create mode 100644 tests/PhpWord/Tests/Shared/XMLReaderTest.php diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 5901046c..9d74e540 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -128,7 +128,7 @@ class Word2007 extends AbstractReader implements ReaderInterface if ($zip->open($filename) === true) { for ($i = 0; $i < $zip->numFiles; $i++) { $xmlFile = $zip->getNameIndex($i); - if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath) { + if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') { $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile)); $this->rels[$docPart] = $this->getRels($filename, $xmlFile, 'word/'); } diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 3c762920..a4f4933d 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -100,6 +100,8 @@ class ListItem extends AbstractStyle /** * Set numbering style name + * + * @param string $value */ public function setNumStyle($value) { diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php index 786248d5..81080232 100644 --- a/tests/PhpWord/Tests/Element/AbstractElementTest.php +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -16,15 +16,23 @@ namespace PhpOffice\PhpWord\Tests\Element; */ class AbstractElementTest extends \PHPUnit_Framework_TestCase { - public function testElementIndex(){ - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); - $ival = rand(0, 100); - $stub->setElementIndex($ival); - $this->assertEquals($stub->getElementIndex(), $ival); + /** + * Test set/get element index + */ + public function testElementIndex() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $ival = rand(0, 100); + $stub->setElementIndex($ival); + $this->assertEquals($stub->getElementIndex(), $ival); } - public function testElementId(){ - $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); - $stub->setElementId(); - $this->assertEquals(strlen($stub->getElementId()), 6); + /** + * Test set/get element unique Id + */ + public function testElementId() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $stub->setElementId(); + $this->assertEquals(strlen($stub->getElementId()), 6); } } diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 3520c376..6ec6743a 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -94,6 +94,9 @@ class ImageTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } + /** + * Test set wrapping style + */ public function testStyleWrappingStyle() { @@ -215,6 +218,6 @@ class ImageTest extends \PHPUnit_Framework_TestCase */ public function testPcxImage() { - $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); + $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); } } diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php index 53ec54be..3fc51f98 100644 --- a/tests/PhpWord/Tests/Element/TableTest.php +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -48,11 +48,11 @@ class TableTest extends \PHPUnit_Framework_TestCase */ public function testStyleArray() { - $oTable = new Table( - 'section', - 1, - array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80) - ); + $oTable = new Table('section', 1, array( + 'borderSize' => 6, + 'borderColor' => '006699', + 'cellMargin' => 80 + )); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle()); } @@ -63,7 +63,7 @@ class TableTest extends \PHPUnit_Framework_TestCase public function testWidth() { $oTable = new Table('section', 1); - $iVal = rand(1, 1000); + $iVal = rand(1, 1000); $oTable->setWidth($iVal); $this->assertEquals($oTable->getWidth(), $iVal); } @@ -73,7 +73,7 @@ class TableTest extends \PHPUnit_Framework_TestCase */ public function testRow() { - $oTable = new Table('section', 1); + $oTable = new Table('section', 1); $element = $oTable->addRow(); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element); $this->assertCount(1, $oTable->getRows()); @@ -84,10 +84,10 @@ class TableTest extends \PHPUnit_Framework_TestCase */ public function testCell() { - $oTable = new Table('section', 1); - $oTable->addRow(); - $element = $oTable->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); } /** @@ -95,12 +95,12 @@ class TableTest extends \PHPUnit_Framework_TestCase */ public function testCountColumns() { - $oTable = new Table('section', 1); - $oTable->addRow(); - $element = $oTable->addCell(); - $this->assertEquals($oTable->countColumns(), 1); - $element = $oTable->addCell(); - $element = $oTable->addCell(); - $this->assertEquals($oTable->countColumns(), 3); + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 1); + $element = $oTable->addCell(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 3); } } diff --git a/tests/PhpWord/Tests/Shared/XMLReaderTest.php b/tests/PhpWord/Tests/Shared/XMLReaderTest.php new file mode 100644 index 00000000..759bf580 --- /dev/null +++ b/tests/PhpWord/Tests/Shared/XMLReaderTest.php @@ -0,0 +1,54 @@ +assertFalse($object->getDomFromZip($filename, 'yadayadaya')); + } + + /** + * Test get elements returns empty + */ + public function testGetElementsReturnsEmpty() + { + $object = new XMLReader(); + $this->assertEquals(array(), $object->getElements('w:document')); + } + + /** + * Test get element returns null + */ + public function testGetElementReturnsNull() + { + $filename = __DIR__ . "/../_files/documents/reader.docx.zip"; + + $object = new XMLReader(); + $object->getDomFromZip($filename, '[Content_Types].xml'); + $element = $object->getElements('*')->item(0); + + $this->assertNull($object->getElement('yadayadaya', $element)); + } +} diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php index 5094d5a1..40bdde68 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -24,8 +24,8 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase public function testAdd() { $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; - $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $object = new ZipArchive(); + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $object = new ZipArchive(); $object->open($zipFile); $object->addFile($existingFile, 'xls/new.xls'); $object->addFromString('content/string.txt', 'Test'); @@ -37,33 +37,39 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase unlink($zipFile); } + /** + * Test find if a given name exists in the archive + */ public function testLocate() { - $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; - $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $object = new ZipArchive(); - $object->open($zipFile); - $object->addFile($existingFile, 'xls/new.xls'); - $object->addFromString('content/string.txt', 'Test'); + $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $object = new ZipArchive(); + $object->open($zipFile); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); - $this->assertEquals(1, $object->locateName('content/string.txt')); - $this->assertFalse($object->locateName('blablabla')); + $this->assertEquals(1, $object->locateName('content/string.txt')); + $this->assertFalse($object->locateName('blablabla')); - unlink($zipFile); + unlink($zipFile); } + /** + * Test returns the name of an entry using its index + */ public function testNameIndex() { - $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; - $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $object = new ZipArchive(); - $object->open($zipFile); - $object->addFile($existingFile, 'xls/new.xls'); - $object->addFromString('content/string.txt', 'Test'); + $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $object = new ZipArchive(); + $object->open($zipFile); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); - $this->assertFalse($object->getNameIndex(-1)); - $this->assertEquals('content/string.txt', $object->getNameIndex(1)); + $this->assertFalse($object->getNameIndex(-1)); + $this->assertEquals('content/string.txt', $object->getNameIndex(1)); - unlink($zipFile); + unlink($zipFile); } } diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index b35c8cb2..fd74d73c 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -32,7 +32,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase 'align' => 'left', 'marginTop' => 240, 'marginLeft' => 240, - 'wrappingStyle' => 'inline', + 'wrappingStyle' => 'inline' ); foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -54,7 +54,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase 'height' => 200, 'align' => 'left', 'marginTop' => 240, - 'marginLeft' => 240, + 'marginLeft' => 240 ); foreach ($properties as $key => $value) { $get = "get{$key}"; diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx b/tests/PhpWord/Tests/_files/documents/reader.docx index 2143c628c5132f5948c339538bef2c2fabdab545..5f37ef4b17d05dc992c92922b5591eb978a429a8 100644 GIT binary patch delta 62792 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 eR8Tm&inr4xu3N`bSu9)up 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 From 9bb56552927e30594ee4394cc19c1386fa8f62c8 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 12 Apr 2014 12:57:51 +0700 Subject: [PATCH 090/146] Unit test for AbstractStyle --- src/PhpWord/Style/AbstractStyle.php | 4 +- .../Tests/Element/AbstractElementTest.php | 3 +- .../PhpWord/Tests/Style/AbstractStyleTest.php | 66 +++++++++++++++++++ tests/PhpWord/Tests/Style/ListItemTest.php | 12 ++++ 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 tests/PhpWord/Tests/Style/AbstractStyleTest.php diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 45ba17a7..ea77dc70 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -105,13 +105,12 @@ abstract class AbstractStyle /** * Set integer value * - * @param integer|null $value + * @param mixed $value * @param integer|null $default * @return integer|null */ protected function setIntVal($value, $default = null) { - $value = intval($value); if (!is_int($value)) { $value = $default; } @@ -128,7 +127,6 @@ abstract class AbstractStyle */ protected function setFloatVal($value, $default = null) { - $value = floatval($value); if (!is_float($value)) { $value = $default; } diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php index 81080232..8dbfb5b3 100644 --- a/tests/PhpWord/Tests/Element/AbstractElementTest.php +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -10,7 +10,7 @@ namespace PhpOffice\PhpWord\Tests\Element; /** - * Test class for PhpOffice\PhpWord\Element\Cell + * Test class for PhpOffice\PhpWord\Element\AbstractElement * * @runTestsInSeparateProcesses */ @@ -26,6 +26,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase $stub->setElementIndex($ival); $this->assertEquals($stub->getElementIndex(), $ival); } + /** * Test set/get element unique Id */ diff --git a/tests/PhpWord/Tests/Style/AbstractStyleTest.php b/tests/PhpWord/Tests/Style/AbstractStyleTest.php new file mode 100644 index 00000000..a9eace9d --- /dev/null +++ b/tests/PhpWord/Tests/Style/AbstractStyleTest.php @@ -0,0 +1,66 @@ +getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + $stub->setStyleByArray(array('index' => 1)); + + $this->assertEquals(1, $stub->getIndex()); + } + + /** + * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with normal value + */ + public function testSetValNormal() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + + $this->assertEquals(true, self::callProtectedMethod($stub, 'setBoolVal', array(true, false))); + $this->assertEquals(12, self::callProtectedMethod($stub, 'setIntVal', array(12, 200))); + $this->assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', array(871.1, 2.1))); + $this->assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', array('a', array('a', 'b'), 'b'))); + } + + /** + * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with default value + */ + public function testSetValDefault() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + + $this->assertEquals(false, self::callProtectedMethod($stub, 'setBoolVal', array('a', false))); + $this->assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', array('foo', 200))); + $this->assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', array('foo', 2.1))); + $this->assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', array('z', array('a', 'b'), 'b'))); + } + + /** + * Helper function to call protected method + */ + public static function callProtectedMethod($object, $method, array $args = array()) + { + $class = new \ReflectionClass(get_class($object)); + $method = $class->getMethod($method); + $method->setAccessible(true); + return $method->invokeArgs($object, $args); + } +} diff --git a/tests/PhpWord/Tests/Style/ListItemTest.php b/tests/PhpWord/Tests/Style/ListItemTest.php index 0fb67da3..6eef720c 100644 --- a/tests/PhpWord/Tests/Style/ListItemTest.php +++ b/tests/PhpWord/Tests/Style/ListItemTest.php @@ -53,4 +53,16 @@ class ListItemTest extends \PHPUnit_Framework_TestCase $object->setListType($value); $this->assertEquals($value, $object->getListType()); } + + /** + * Test set/get numbering style name + */ + public function testSetGetNumStyle() + { + $expected = 'List Name'; + + $object = new ListItem(); + $object->setNumStyle($expected); + $this->assertEquals($expected, $object->getNumStyle()); + } } From a5b5e0cff015ebcedae807892fd4b7476dc0a4de Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 17:43:03 +0700 Subject: [PATCH 091/146] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a932eda..937930e8 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ This release marked heavy refactorings on internal code structure with the creat - Writer: New 'ODText\Base` class - @ivanlanin GH-187 - General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin - General: Add some unit tests for Shared & Element (100%!) - @Progi1984 +- Test: Add some samples and tests for image wrapping style - @brunocasado GH-59 ## 0.9.1 - 27 Mar 2014 From e78489b36e5d06055c3c18091f362fc7d4a1077f Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 18:03:59 +0700 Subject: [PATCH 092/146] Update unit test and changelog --- CHANGELOG.md | 1 + src/PhpWord/Element/Image.php | 11 ++++++----- tests/PhpWord/Tests/Element/ImageTest.php | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 937930e8..70f53abf 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This release marked heavy refactorings on internal code structure with the creat - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin +- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 ### Bugfixes diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 139c578f..ce4b1609 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -133,14 +133,15 @@ class Image extends AbstractElement $this->style = $this->setStyle(new ImageStyle(), $style, true); $styleWidth = $this->style->getWidth(); $styleHeight = $this->style->getHeight(); + list($actualWidth, $actualHeight) = $imgData; if (!($styleWidth && $styleHeight)) { if ($styleWidth == null && $styleHeight == null) { - $this->style->setWidth($imgData[0]); - $this->style->setHeight($imgData[1]); - } else if ($styleWidth) { - $this->style->setHeight($imgData[1] * ($styleWidth / $imgData[0])); + $this->style->setWidth($actualWidth); + $this->style->setHeight($actualHeight); + } elseif ($styleWidth) { + $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth)); } else { - $this->style->setWidth($imgData[0] * ($styleHeight / $imgData[1])); + $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight)); } } $this->setImageFunctions(); diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index 6ec6743a..eae9fc5f 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -129,7 +129,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase public function testPNG() { $src = __DIR__ . "/../_files/images/firefox.png"; - $oImage = new Image($src); + $oImage = new Image($src, array('width' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); @@ -146,7 +146,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase public function testGIF() { $src = __DIR__ . "/../_files/images/mario.gif"; - $oImage = new Image($src); + $oImage = new Image($src, array('height' => 100)); $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); $this->assertEquals($oImage->getSource(), $src); From 19a69e2c39d91f56eefaf2e6cb0ec1888c972b04 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sat, 12 Apr 2014 10:12:24 +0700 Subject: [PATCH 093/146] Basic HTML writer --- CHANGELOG.md | 3 +- samples/Sample_01_SimpleText.php | 12 +- samples/Sample_02_TabStops.php | 12 +- samples/Sample_03_Sections.php | 12 +- samples/Sample_04_Textrun.php | 12 +- samples/Sample_05_Multicolumn.php | 12 +- samples/Sample_06_Footnote.php | 12 +- samples/Sample_08_ParagraphPagination.php | 12 +- samples/Sample_09_Tables.php | 12 +- samples/Sample_10_EastAsianFontStyle.php | 12 +- samples/Sample_11_ReadWord2007.php | 13 +- samples/Sample_12_HeaderFooter.php | 13 +- samples/Sample_13_Images.php | 13 +- samples/Sample_14_ListItem.php | 13 +- samples/Sample_15_Link.php | 14 +- samples/Sample_16_Object.php | 14 +- samples/Sample_17_TitleTOC.php | 13 +- samples/Sample_18_Watermark.php | 14 +- samples/Sample_19_TextBreak.php | 14 +- samples/Sample_20_BGColor.php | 12 +- samples/Sample_21_TableRowRules.php | 12 +- samples/Sample_22_CheckBox.php | 12 +- samples/Sample_Footer.php | 23 - samples/Sample_Header.php | 50 ++ samples/index.php | 6 +- src/PhpWord/Element/Title.php | 10 + src/PhpWord/IOFactory.php | 4 +- src/PhpWord/Writer/HTML.php | 589 ++++++++++++++++++++++ tests/PhpWord/Tests/Writer/HTMLTest.php | 105 ++++ 29 files changed, 826 insertions(+), 229 deletions(-) create mode 100644 src/PhpWord/Writer/HTML.php create mode 100644 tests/PhpWord/Tests/Writer/HTMLTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 03400d46..f9bcdd19 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.10.0 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML writer is initiated. ### Features @@ -31,6 +31,7 @@ This release marked heavy refactorings on internal code structure with the creat - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin +- HTML Writer: Basic HTML writer initiated - @ivanlanin ### Bugfixes diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index 02b78bd7..659686d3 100755 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -45,13 +45,7 @@ $section->addTextBreak(); $section->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index dbed59a3..d6e4cdbc 100755 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -33,13 +33,7 @@ $section->addText("Left Aligned\tRight Aligned", null, 'rightTab'); $section->addText("\tCenter Aligned", null, 'centerTab'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index 4953b6a6..bfbc84af 100755 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -26,13 +26,7 @@ $section->addHeader()->addText('Header'); $section->addFooter()->addText('Footer'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 354eadfd..f415ca17 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -34,13 +34,7 @@ $textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 478a8dd0..a3083824 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -36,13 +36,7 @@ $section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again.'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index 75120088..1bec44e4 100755 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -38,13 +38,7 @@ $footnote = $section->addFootnote(); $footnote->addText('The reference for this is wrapped in its own line'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index bf1400a0..57fbab09 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -46,13 +46,7 @@ $section->addText('Paragraph with pageBreakBefore = true (default: false). ' . null, array('pageBreakBefore' => true)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index 5af73fb6..fd930b2b 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -85,13 +85,7 @@ $table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); $table->addCell(null, $cellRowContinue); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 39f449c3..44bca8a6 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -10,13 +10,7 @@ $header = array('size' => 16, 'bold' => true); $section->addText('中文楷体样式测试',array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index e5112e2e..09d9cab0 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -7,13 +7,8 @@ $source = "resources/{$name}.docx"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source); -// (Re)write contents -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 15309041..8e053286 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -59,15 +59,8 @@ $sec2Header->addText("All pages in Section 2 will Have this!"); $section2->addTextBreak(); $section2->addText('Some text...'); - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 4ef325b8..c8199cce 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -18,16 +18,9 @@ $section->addTextBreak(2); $source = 'http://php.net/images/logos/php-med-trans-light.gif'; $section->addText("Remote image from: {$source}"); $section->addImage($source); -// End code // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 45d9c1a7..cd22df8e 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -54,15 +54,8 @@ $section->addListItem('List Item 6', 1, 'myOwnStyle', $predefinedMultilevel, 'P- $section->addListItem('List Item 7', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); $section->addTextBreak(2); - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index c4435ac0..1bd61e79 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -16,16 +16,8 @@ $phpWord->addLinkStyle('myOwnLinkStyle', array('bold'=>true, 'color'=>'808000')) $section->addLink('http://www.bing.com', null, 'myOwnLinkStyle'); $section->addLink('http://www.yahoo.com', null, 'myOwnLinkStyle'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index cb8de6db..af23a00f 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -11,16 +11,8 @@ $section->addText('You can open this OLE object by double clicking on the icon:' $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 15de531b..b18b1bc9 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -67,16 +67,9 @@ $section->addTitle('Subtitle 3.1.2', 3); $section->addText('Text'); echo date('H:i:s'), " Note: Please refresh TOC manually.", EOL; -// End code // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index d0ea786a..313cfbed 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -12,16 +12,8 @@ $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); $section->addText('The header reference to the current section includes a watermark image.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index d7e11ea4..a209ce39 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -25,16 +25,8 @@ $section->addText('Text break with inline paragraph style:'); $section->addTextBreak(1, null, $paragraphStyle); $section->addText('Done.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index fec40859..892cd8b2 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -11,13 +11,7 @@ $section->addText("This one uses bgColor and is using hex value (0xfbbb10)", arr $section->addText("Compatible with font colors", array("color"=>"0000ff", "bgColor" => "fbbb10")); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 10ad156d..b600ec00 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -28,13 +28,7 @@ $section->addText("In this example, image is 250px height. Rows are calculated i $section->addText("So: $"."table2->addRow(3750, array('exactHeight'=>true));"); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 89827388..e7aae5ba 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -15,13 +15,7 @@ $cell = $table->addCell(); $cell->addCheckBox('chkBox2', 'Checkbox 2'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_Footer.php b/samples/Sample_Footer.php index 4d5777c2..f7e2305f 100644 --- a/samples/Sample_Footer.php +++ b/samples/Sample_Footer.php @@ -2,33 +2,10 @@ /** * Footer file */ -// Do not show execution time for index -if (!IS_INDEX) { - echo date('H:i:s'), " Done writing file(s)", EOL; - echo date('H:i:s'), " Peak memory usage: ", (memory_get_peak_usage(true) / 1024 / 1024), " MB", EOL; -} -// Show message when executed with CLI, show links when using browsers -if (CLI) { - echo 'The results are stored in the "results" subdirectory.', EOL; -} else { - if (!IS_INDEX) { - $types = array('docx', 'odt', 'rtf'); - echo '

 

'; - echo '

Results: '; - foreach ($types as $type) { - $result = 'results/' . SCRIPT_FILENAME . '.' . $type; - if (file_exists($result)) { - echo "{$type} "; - } - } - echo '

'; - } ?>
-{$pageHeading}"; + +// Set writers +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html'); + // Populate samples $files = ''; if ($handle = opendir('.')) { @@ -32,6 +36,52 @@ if ($handle = opendir('.')) { } closedir($handle); } + +/** + * Get results + * + * @param array $writers + * @param string $filename + * @return string + */ +function write($phpWord, $filename, $writers) +{ + $result = ''; + + // Write + foreach ($writers as $writer => $extension) { + $result .= date('H:i:s') . " Write to {$writer} format" . EOL; + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter->save("{$filename}.{$extension}"); + rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + } + + // Do not show execution time for index + if (!IS_INDEX) { + $result .= date('H:i:s') . " Done writing file(s)" . EOL; + $result .= date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB" . EOL; + } + + // Return + if (CLI) { + $result .= 'The results are stored in the "results" subdirectory.' . EOL; + } else { + if (!IS_INDEX) { + $types = array_values($writers); + $result .= '

 

'; + $result .= '

Results: '; + foreach ($types as $type) { + $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type; + if (file_exists($resultFile)) { + $result .= "{$type} "; + } + } + $result .= '

'; + } + } + + return $result; +} ?> <?php echo $pageTitle; ?> diff --git a/samples/index.php b/samples/index.php index 451cf381..8c742729 100644 --- a/samples/index.php +++ b/samples/index.php @@ -24,5 +24,7 @@ foreach ($requirements as $key => $value) { echo "
  • {$value[0]} ... {$status}
  • "; } echo ""; -} // if (!CLI) -include_once 'Sample_Footer.php'; +} +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 5ed1bfbc..93b48d62 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -119,6 +119,16 @@ class Title extends AbstractElement return $this->text; } + /** + * Get depth + * + * @return integer + */ + public function getDepth() + { + return $this->depth; + } + /** * Get Title style * diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index ade4398e..c15ec821 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -28,7 +28,7 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'WriterInterface' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { + if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { throw new Exception("\"{$name}\" is not a valid writer."); } @@ -45,7 +45,7 @@ abstract class IOFactory */ public static function createReader($name = 'Word2007') { - if ($name !== 'ReaderInterface' && $name !== 'Word2007') { + if (!in_array($name, array('ReaderInterface', 'Word2007'))) { throw new Exception("\"{$name}\" is not a valid reader."); } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php new file mode 100644 index 00000000..797dd9dc --- /dev/null +++ b/src/PhpWord/Writer/HTML.php @@ -0,0 +1,589 @@ +setPhpWord($phpWord); + } + + /** + * Save PhpWord to file + * + * @param string $filename + * @throws Exception + */ + public function save($filename = null) + { + if (!is_null($this->getPhpWord())) { + $hFile = fopen($filename, 'w') or die("can't open file"); + fwrite($hFile, $this->writeDocument()); + fclose($hFile); + } else { + throw new Exception("No PHPWord assigned."); + } + } + + /** + * Get phpWord data + * + * @return string + */ + private function writeDocument() + { + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLHead(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLBody(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + + return $html; + } + + /** + * Generate HTML header + * + * @return string + */ + public function writeHTMLHead() + { + $properties = $this->getPhpWord()->getDocumentProperties(); + $propertiesMapping = array( + 'creator' => 'author', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' + ); + $title = $properties->getTitle(); + $title = ($title != '') ? $title : 'PHPWord'; + + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . htmlspecialchars($title) . '' . PHP_EOL; + foreach ($propertiesMapping as $key => $value) { + $value = ($value == '') ? $key : $value; + $method = "get" . $key; + if ($properties->$method() != '') { + $html .= '' . PHP_EOL; + } + } + $html .= $this->writeStyles(); + + return $html; + } + + /** + * Get content + * + * @return string + */ + public function writeHTMLBody() + { + $phpWord = $this->getPhpWord(); + $html = ''; + + $sections = $phpWord->getSections(); + $countSections = count($sections); + $pSection = 0; + + if ($countSections > 0) { + foreach ($sections as $section) { + $pSection++; + $cellContents = $section->getElements(); + foreach ($cellContents as $element) { + if ($element instanceof Text) { + $html .= $this->writeText($element); + } elseif ($element instanceof TextRun) { + $html .= $this->writeTextRun($element); + } elseif ($element instanceof Link) { + $html .= $this->writeLink($element); + } elseif ($element instanceof Title) { + $html .= $this->writeTitle($element); + } elseif ($element instanceof PreserveText) { + $html .= $this->writePreserveText($element); + } elseif ($element instanceof TextBreak) { + $html .= $this->writeTextBreak($element); + } elseif ($element instanceof PageBreak) { + $html .= $this->writePageBreak($element); + } elseif ($element instanceof Table) { + $html .= $this->writeTable($element); + } elseif ($element instanceof ListItem) { + $html .= $this->writeListItem($element); + } elseif ($element instanceof Image) { + $html .= $this->writeImage($element); + } elseif ($element instanceof Object) { + $html .= $this->writeObject($element); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + } + } + + return $html; + } + + /** + * Get text + * + * @param Text $text + * @param boolean $withoutP + * @return string + */ + private function writeText($text, $withoutP = false) + { + $html = ''; + $paragraphStyle = $text->getParagraphStyle(); + $spIsObject = ($paragraphStyle instanceof Paragraph); + $fontStyle = $text->getFontStyle(); + $sfIsObject = ($fontStyle instanceof Font); + + if ($paragraphStyle && !$withoutP) { + $html .= 'writeParagraphStyle($paragraphStyle) . '"'; + } + $html .= '>'; + } + if ($fontStyle) { + $html .= 'writeFontStyle($fontStyle) . '"'; + } + $html .= '>'; + } + $html .= htmlspecialchars($text->getText()); + if ($fontStyle) { + $html .= ''; + } + if ($paragraphStyle && !$withoutP) { + $html .= '

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Get text run content + * + * @param TextRun $textrun + * @return string + */ + private function writeTextRun($textrun) + { + $html = ''; + $elements = $textrun->getElements(); + if (count($elements) > 0) { + $paragraphStyle = $textrun->getParagraphStyle(); + $spIsObject = ($paragraphStyle instanceof Paragraph); + $html .= 'writeParagraphStyle($paragraphStyle) . '"'; + } + } + $html .= '>'; + foreach ($elements as $element) { + if ($element instanceof Text) { + $html .= $this->writeText($element, true); + } elseif ($element instanceof Link) { + $html .= $this->writeLink($element, true); + } elseif ($element instanceof TextBreak) { + $html .= $this->writeTextBreak($element, true); + } elseif ($element instanceof Image) { + $html .= $this->writeImage($element, true); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + $html .= '

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Write link + * + * @param Link $element + * @return string + */ + private function writeLink($element, $withoutP = false) + { + $url = $element->getLinkSrc(); + $text = $element->getLinkName(); + $html = ''; + if (!$withoutP) { + $html .= "

    " . PHP_EOL; + } + $html .= "{$text}" . PHP_EOL; + if (!$withoutP) { + $html .= "

    " . PHP_EOL; + } + + return $html; + } + + /** + * Write heading + * + * @param Title $element + * @return string + */ + private function writeTitle($element) + { + $tag = 'h' . $element->getDepth(); + $text = htmlspecialchars($element->getText()); + $html = "<{$tag}>{$text}" . PHP_EOL; + + return $html; + } + + /** + * Write preserve text + * + * @param PreserveText $element + * @return string + */ + private function writePreserveText($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Get text break + * + * @param TextBreak $element + * @param boolean $withoutP + * @return string + */ + private function writeTextBreak($element, $withoutP = false) + { + if ($withoutP) { + $html = '
    ' . PHP_EOL; + } else { + $html = '

     

    ' . PHP_EOL; + } + + return $html; + } + + /** + * Write page break + * + * @param PageBreak $element + * @return string + */ + private function writePageBreak($element) + { + return $this->writeUnsupportedElement($element, false); + } + + /** + * Write list item + * + * @param ListItem $element + * @return string + */ + private function writeListItem($element) + { + return $this->writeUnsupportedElement($element, false); + } + + /** + * Write table + * + * @param Title $element + * @return string + */ + private function writeTable($element) + { + $html = ''; + $rows = $element->getRows(); + $cRows = count($rows); + if ($cRows > 0) { + $html .= "" . PHP_EOL; + foreach ($rows as $row) { + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $html .= "" . PHP_EOL; + foreach ($row->getCells() as $cell) { + $cellTag = $tblHeader ? 'th' : 'td'; + $cellContents = $cell->getElements(); + $html .= "<{$cellTag}>" . PHP_EOL; + if (count($cellContents) > 0) { + foreach ($cellContents as $content) { + if ($content instanceof Text) { + $html .= $this->writeText($content); + } elseif ($content instanceof TextRun) { + $html .= $this->writeTextRun($content); + } elseif ($content instanceof Link) { + $html .= $this->writeLink($content); + } elseif ($content instanceof PreserveText) { + $html .= $this->writePreserveText($content); + } elseif ($content instanceof TextBreak) { + $html .= $this->writeTextBreak($content); + } elseif ($content instanceof ListItem) { + $html .= $this->writeListItem($content); + } elseif ($content instanceof Image) { + $html .= $this->writeImage($content); + } elseif ($content instanceof Object) { + $html .= $this->writeObject($content); + } elseif ($element instanceof Footnote) { + $html .= $this->writeFootnote($element, true); + } elseif ($element instanceof Endnote) { + $html .= $this->writeEndnote($element, true); + } + } + } else { + $this->writeTextBreak($content); + } + $html .= "" . PHP_EOL; + } + $html .= "" . PHP_EOL; + } + $html .= "
    " . PHP_EOL; + } + + return $html; + } + + /** + * Write image + * + * @param Image $element + * @return string + */ + private function writeImage($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Write object + * + * @param Object $element + * @return string + */ + private function writeObject($element, $withoutP = false) + { + return $this->writeUnsupportedElement($element, $withoutP); + } + + /** + * Write footnote + * + * @param Footnote $element + * @return string + */ + private function writeFootnote($element) + { + return $this->writeUnsupportedElement($element, true); + } + + /** + * Write endnote + * + * @param Endnote $element + * @return string + */ + private function writeEndnote($element) + { + return $this->writeUnsupportedElement($element, true); + } + + /** + * Write unsupported element + * + * @param mixed $element + * @param boolean $withoutP + * @return string + */ + private function writeUnsupportedElement($element, $withoutP = false) + { + $elementClass = get_class($element); + $elementMark = str_replace('PhpOffice\\PhpWord\\Element\\', '', $elementClass); + $elementMark = htmlentities("<{$elementMark}>"); + if ($withoutP) { + $html = "{$elementMark}" . PHP_EOL; + } else { + $html = "

    {$elementMark}

    " . PHP_EOL; + } + + return $html; + } + + /** + * Get styles + * + * @return string + */ + private function writeStyles() + { + $css = '' . PHP_EOL; + + return $css; + } + + /** + * Get font style + * + * @param Font $style + * @param boolean $curlyBracket + * @return string + */ + private function writeFontStyle($style, $curlyBracket = false) + { + $css = array(); + if (PHPWord::DEFAULT_FONT_NAME != $style->getName()) { + $css['font-family'] = "'" . $style->getName() . "'"; + } + if (PHPWord::DEFAULT_FONT_SIZE != $style->getSize()) { + $css['font-size'] = $style->getSize() . 'pt'; + } + if (PHPWord::DEFAULT_FONT_COLOR != $style->getColor()) { + $css['color'] = '#' . $style->getColor(); + } + $css['background'] = $style->getFgColor(); + if ($style->getBold()) { + $css['font-weight'] = 'bold'; + } + if ($style->getItalic()) { + $css['font-style'] = 'italic'; + } + if ($style->getSuperScript()) { + $css['vertical-align'] = 'super'; + } elseif ($style->getSubScript()) { + $css['vertical-align'] = 'sub'; + } + $css['text-decoration'] = ''; + if ($style->getUnderline() != Font::UNDERLINE_NONE) { + $css['text-decoration'] .= 'underline '; + } + if ($style->getStrikethrough()) { + $css['text-decoration'] .= 'line-through '; + } + + return $this->assembleCss($css, $curlyBracket); + } + + /** + * Get paragraph style + * + * @param Paragraph $style + * @param boolean $curlyBracket + * @return string + */ + private function writeParagraphStyle($style, $curlyBracket = false) + { + $css = array(); + if ($style->getAlign()) { + $css['text-align'] = $style->getAlign(); + } + + return $this->assembleCss($css, $curlyBracket); + } + + /** + * Takes array where of CSS properties / values and converts to CSS string + * + * @param array $css + * @param boolean $curlyBracket + * @return string + */ + private function assembleCss($css, $curlyBracket = false) + { + $pairs = array(); + foreach ($css as $key => $value) { + if ($value != '') { + $pairs[] = $key . ': ' . $value; + } + } + $string = implode('; ', $pairs); + if ($curlyBracket) { + $string = '{ ' . $string . ' }'; + } + + return $string; + } +} diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php new file mode 100644 index 00000000..40ea88b0 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -0,0 +1,105 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); + } + + /** + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage No PhpWord assigned. + */ + public function testConstructWithNull() + { + $object = new HTML(); + $object->getPhpWord(); + } + + /** + * Save + */ + public function testSave() + { + $imageSrc = __DIR__ . "/../_files/images/PhpWord.png"; + $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; + $file = __DIR__ . "/../_files/temp.html"; + + $phpWord = new PhpWord(); + + $docProps = $phpWord->getDocumentProperties(); + $docProps->setTitle('HTML Test'); + + $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); + $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $section = $phpWord->addSection(); + $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addTextBreak(); + $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); + $section->addLink('http://test.com'); + $section->addTitle('Test', 1); + $section->addPageBreak(); + $section->addListItem('Test'); + $section->addImage($imageSrc); + $section->addObject($objectSrc); + $section->addFootnote(); + $section->addEndnote(); + + $section = $phpWord->addSection(); + + $textrun = $section->addTextRun(array('align' => 'center')); + $textrun->addText('Test 3'); + $textrun->addTextBreak(); + + $textrun = $section->addTextRun('Paragraph'); + $textrun->addLink('http://test.com'); + $textrun->addImage($imageSrc); + $textrun->addFootnote(); + $textrun->addEndnote(); + + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $cell = $table->addRow()->addCell(); + $cell->addText('Test 1', array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true)); + $cell->addTextRun(); + $cell->addLink('http://test.com'); + $cell->addTextBreak(); + $cell->addListItem('Test'); + $cell->addImage($imageSrc); + $cell->addObject($objectSrc); + $cell->addFootnote(); + $cell->addEndnote(); + + $writer = new HTML($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } +} From 5a01927b1622b3e3a1cb34cb76fb77dc04a9dd38 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 22:25:42 +0700 Subject: [PATCH 094/146] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806c9c1c..d6b7bfb5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ This release marked heavy refactorings on internal code structure with the creat - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin - Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 -- HTML Writer: Basic HTML writer initiated - @ivanlanin +- HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147 ### Bugfixes From 580a61a832929312cb7bc7fe6aba72fd00ab147f Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 13 Apr 2014 23:17:39 +0700 Subject: [PATCH 095/146] Basic PDF Writer #68 --- CHANGELOG.md | 3 +- samples/Sample_Header.php | 26 ++- src/PhpWord/IOFactory.php | 2 +- src/PhpWord/Settings.php | 98 ++++++++- src/PhpWord/Writer/HTML.php | 36 ++-- src/PhpWord/Writer/PDF.php | 66 ++++++ src/PhpWord/Writer/PDF/Core.php | 194 ++++++++++++++++++ src/PhpWord/Writer/PDF/DomPDF.php | 72 +++++++ .../PhpWord/Tests/Style/AbstractStyleTest.php | 4 + 9 files changed, 473 insertions(+), 28 deletions(-) create mode 100644 src/PhpWord/Writer/PDF.php create mode 100644 src/PhpWord/Writer/PDF/Core.php create mode 100644 src/PhpWord/Writer/PDF/DomPDF.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b7bfb5..d8268a73 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This is the changelog between releases of PHPWord. Releases are listed in revers ## 0.10.0 - Not yet released -This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML support is enabled. +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. ### Features @@ -33,6 +33,7 @@ This release marked heavy refactorings on internal code structure with the creat - ODT Writer: Basic table writing support - @ivanlanin - Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 - HTML Writer: Basic HTML writer initiated - @ivanlanin GH-203 GH-67 GH-147 +- PDF Writer: Basic PDF writer initiated using DomPDF - @ivanlanin GH-68 ### Bugfixes diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index e3057db7..04fd8a40 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -11,6 +11,16 @@ define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); +// Set writers +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); + +// Set PDF renderer +$rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF; +$rendererLibraryPath = ""; // Put dompdf library path +if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) { + $writers['PDF'] = null; +} + // Return to the caller script when runs by CLI if (CLI) { return; @@ -22,9 +32,6 @@ $pageTitle = IS_INDEX ? 'Welcome to ' : "{$pageHeading} - "; $pageTitle .= 'PHPWord'; $pageHeading = IS_INDEX ? '' : "

    {$pageHeading}

    "; -// Set writers -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html'); - // Populate samples $files = ''; if ($handle = opendir('.')) { @@ -51,10 +58,15 @@ function write($phpWord, $filename, $writers) // Write foreach ($writers as $writer => $extension) { - $result .= date('H:i:s') . " Write to {$writer} format" . EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$filename}.{$extension}"); - rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + $result .= date('H:i:s') . " Write to {$writer} format"; + if (!is_null($extension)) { + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter->save("{$filename}.{$extension}"); + rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + } else { + $result .= ' ... NOT DONE!'; + } + $result .= EOL; } // Do not show execution time for index diff --git a/src/PhpWord/IOFactory.php b/src/PhpWord/IOFactory.php index c15ec821..9f7c8162 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -28,7 +28,7 @@ abstract class IOFactory */ public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML'))) { + if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML', 'PDF'))) { throw new Exception("\"{$name}\" is not a valid writer."); } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 0af6cf72..4558736b 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -14,10 +14,13 @@ namespace PhpOffice\PhpWord; */ class Settings { - /** Available Zip library classes */ + /** Available Zip library classes */ const PCLZIP = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; const ZIPARCHIVE = 'ZipArchive'; + /** Optional PDF Rendering libraries */ + const PDF_RENDERER_DOMPDF = 'DomPDF'; + /** * Compatibility option for XMLWriter * @@ -27,13 +30,32 @@ class Settings /** * Name of the class used for Zip file management - * e.g. - * ZipArchive * * @var string */ private static $zipClass = self::ZIPARCHIVE; + /** + * Name of the classes used for PDF renderer + * + * @var array + */ + private static $pdfRenderers = array(self::PDF_RENDERER_DOMPDF); + + /** + * Name of the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererName = null; + + /** + * Directory Path to the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererPath = null; + /** * Set the compatibility option used by the XMLWriter * @@ -74,7 +96,7 @@ class Settings return true; } return false; - } // function setZipClass() + } /** * Return the name of the Zip handler Class that PHPWord is configured to use (PCLZip or ZipArchive) @@ -87,5 +109,71 @@ class Settings public static function getZipClass() { return self::$zipClass; - } // function getZipClass() + } + + /** + * Set details of the external library for rendering PDF files + * + * @param string $libraryName + * @param string $libraryBaseDir + * @return boolean Success or failure + */ + public static function setPdfRenderer($libraryName, $libraryBaseDir) + { + if (!self::setPdfRendererName($libraryName)) { + return false; + } + + return self::setPdfRendererPath($libraryBaseDir); + } + + /** + * Return the PDF Rendering Library + */ + public static function getPdfRendererName() + { + return self::$pdfRendererName; + } + + /** + * Identify the external library to use for rendering PDF files + * + * @param string $libraryName + * @return boolean Success or failure + */ + public static function setPdfRendererName($libraryName) + { + if (!in_array($libraryName, self::$pdfRenderers)) { + return false; + } + + self::$pdfRendererName = $libraryName; + + return true; + } + + + /** + * Return the directory path to the PDF Rendering Library + */ + public static function getPdfRendererPath() + { + return self::$pdfRendererPath; + } + + /** + * Location of external library to use for rendering PDF files + * + * @param string $libraryBaseDir Directory path to the library's base folder + * @return boolean Success or failure + */ + public static function setPdfRendererPath($libraryBaseDir) + { + if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) { + return false; + } + self::$pdfRendererPath = $libraryBaseDir; + + return true; + } } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index 797dd9dc..f0879332 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -16,6 +16,7 @@ use PhpOffice\PhpWord\Element\Link; use PhpOffice\PhpWord\Element\ListItem; use PhpOffice\PhpWord\Element\Object; use PhpOffice\PhpWord\Element\PageBreak; +use PhpOffice\PhpWord\Element\PreserveText; use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Text; use PhpOffice\PhpWord\Element\TextBreak; @@ -65,7 +66,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - private function writeDocument() + public function writeDocument() { $html = ''; $html .= '' . PHP_EOL; @@ -87,7 +88,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - public function writeHTMLHead() + private function writeHTMLHead() { $properties = $this->getPhpWord()->getDocumentProperties(); $propertiesMapping = array( @@ -124,7 +125,7 @@ class HTML extends AbstractWriter implements WriterInterface * * @return string */ - public function writeHTMLBody() + private function writeHTMLBody() { $phpWord = $this->getPhpWord(); $html = ''; @@ -136,8 +137,8 @@ class HTML extends AbstractWriter implements WriterInterface if ($countSections > 0) { foreach ($sections as $section) { $pSection++; - $cellContents = $section->getElements(); - foreach ($cellContents as $element) { + $contents = $section->getElements(); + foreach ($contents as $element) { if ($element instanceof Text) { $html .= $this->writeText($element); } elseif ($element instanceof TextRun) { @@ -161,9 +162,9 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($element instanceof Object) { $html .= $this->writeObject($element); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } } @@ -248,9 +249,9 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($element instanceof Image) { $html .= $this->writeImage($element, true); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } $html .= '

    ' . PHP_EOL; @@ -263,6 +264,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write link * * @param Link $element + * @param boolean $withoutP * @return string */ private function writeLink($element, $withoutP = false) @@ -300,6 +302,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write preserve text * * @param PreserveText $element + * @param boolean $withoutP * @return string */ private function writePreserveText($element, $withoutP = false) @@ -350,7 +353,7 @@ class HTML extends AbstractWriter implements WriterInterface /** * Write table * - * @param Title $element + * @param Table $element * @return string */ private function writeTable($element) @@ -361,7 +364,7 @@ class HTML extends AbstractWriter implements WriterInterface if ($cRows > 0) { $html .= "" . PHP_EOL; foreach ($rows as $row) { - $height = $row->getHeight(); + // $height = $row->getHeight(); $rowStyle = $row->getStyle(); $tblHeader = $rowStyle->getTblHeader(); $html .= "" . PHP_EOL; @@ -388,13 +391,13 @@ class HTML extends AbstractWriter implements WriterInterface } elseif ($content instanceof Object) { $html .= $this->writeObject($content); } elseif ($element instanceof Footnote) { - $html .= $this->writeFootnote($element, true); + $html .= $this->writeFootnote($element); } elseif ($element instanceof Endnote) { - $html .= $this->writeEndnote($element, true); + $html .= $this->writeEndnote($element); } } } else { - $this->writeTextBreak($content); + $html .= $this->writeTextBreak(new TextBreak()); } $html .= "" . PHP_EOL; } @@ -410,6 +413,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write image * * @param Image $element + * @param boolean $withoutP * @return string */ private function writeImage($element, $withoutP = false) @@ -421,6 +425,7 @@ class HTML extends AbstractWriter implements WriterInterface * Write object * * @param Object $element + * @param boolean $withoutP * @return string */ private function writeObject($element, $withoutP = false) @@ -478,11 +483,14 @@ class HTML extends AbstractWriter implements WriterInterface */ private function writeStyles() { + $bodyCss = array(); $css = '

    Results: '; foreach ($types as $type) { - $result = "results/{$sampleFile}.{$type}"; + $result = 'results/' . SCRIPT_FILENAME . '.' . $type; if (file_exists($result)) { echo "{$type} "; } diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 28ae61e7..b61e415a 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -5,6 +5,8 @@ error_reporting(E_ALL); define('CLI', (PHP_SAPI == 'cli') ? true : false); define('EOL', CLI ? PHP_EOL : '
    '); +define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php')); +define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; PhpOffice\PhpWord\Autoloader::register(); @@ -15,12 +17,10 @@ if (CLI) { } // Set titles and names -$sampleFile = basename($_SERVER['SCRIPT_FILENAME'], '.php'); -$isIndexFile = ($sampleFile == 'index'); -$pageHeading = str_replace('_', ' ', $sampleFile); -$pageTitle = $isIndexFile ? 'Welcome to ' : "{$pageHeading} - "; +$pageHeading = str_replace('_', ' ', SCRIPT_FILENAME); +$pageTitle = IS_INDEX ? 'Welcome to ' : "{$pageHeading} - "; $pageTitle .= 'PHPWord'; -$pageHeading = $isIndexFile ? '' : "