#遭遇したケース
phpで帳票を出力する事があり、WORD出力指定。
phpwordを使って出力。
ただ帳票出力なので表が細かい。
数百人分一括出力が必要。(1人1ページ、各名前や住所、数字等を変数で出力)
#挫折した方法
- 丁寧に1行1行出力していく→表の細かさで挫折
- XMLで<w:body>内を抜き出してループで連結し、ヘッダとフッタをくっつけて出力→うまく保存されず
- なにかライブラリ内にそういう機能ないのか?!→見つからず
#採用した方式
人単位でループするたびにテンプレート読み込み、テンプレートに設置した変数にsetValueしていく。
ループ最後にユニークIDで人数分のファイルを出力。
その後全ループ終了後(ファイル出力終了後)にファイルを連結してダウンロードさせる。
docxの連結はDocxMergeというライブラリを使用。
https://github.com/krustnic/DocxMerge
ここでは個別にファイルを出力する方法は割愛します。
phpwordをcomposerで導入した人はそのままcomposerでインストールしてください。
個別に設定する方はダウンロードしてrequireすれば多分大丈夫です。
#Merge Exampleがちょっと不親切なので・・
require "vendor/autoload.php";
use DocxMerge\DocxMerge;
$dm = new DocxMerge();
$dm->merge( [
"templates/TplPage1.docx",
"templates/TplPage2.docx"
], "/tmp/result.docx" );
こんなサンプルがありますが、まあなんとなく、最初に連結するファイルを指定して、最後に連結完了後のファイル名を指定しているんだろうな、とわかると思います。
まあ正しいのですが・・最初の連結対象ファイルは配列でした。
なので文字列を生成するのではなく、ループ中にファイル名を含むパスを生成してください。
var_dump($ids);
array(4) {
[0]=>
string(17) "/path/to/001.docx"
[1]=>
string(17) "/path/to/002.docx"
[2]=>
string(17) "/path/to/003.docx"
[3]=>
string(17) "/path/to/004.docx"
}
こんな配列を作って、
$dm = new DocxMerge();
$dm->merge([$ids], '/path/to/result.docx');
をすれは完了かと思いましたが、ライブラリがエラー吐いてきます。
copyの値が配列だよとかなんとか。
ソースを見る限り、配列になっているようには思えなかったのですが、
DocxMerge.phpの
public function merge( $docxFilesArray, $outDocxFilePath ) {
の下でvar_dump($docxFilesArray)してみると、
array(1) {
[0]=>
array(4) {
[0]=>
string(17) "/path/to/001.docx"
[1]=>
string(17) "/path/to/002.docx"
[2]=>
string(17) "/path/to/003.docx"
[3]=>
string(17) "/path/to/004.docx"
}
}
何故か配列が変わっています。
なぜ配列が変わっている!と調べるもの面倒だったので、2箇所修正したら動きました。
DocxMerge.php: 30
if ( !copy( $docxFilesArray[0], $outDocxFilePath ) ) {
↓
if ( !copy( $docxFilesArray[0][0], $outDocxFilePath ) ) {
DocxMerge.php: 36-37
for( $i=1; $i<count( $docxFilesArray ); $i++ ) {
$docx->addFile( $docxFilesArray[$i], "part".$i.".docx", "rId10".$i );
↓
for( $i=1; $i<count( $docxFilesArray[0] ); $i++ ) {
$docx->addFile( $docxFilesArray[0][$i], "part".$i.".docx", "rId10".$i );
これで連結成功しました。
#連結してみると、ディレクトリ内に大量のゴミが・・
自分でゴミは片付けましょう。
$gomi = /path/to/*.tmp';
foreach (glob($gomi) as $val) {
unlink($val);
}