LoginSignup
3
2

More than 5 years have passed since last update.

phpwordでテンプレートを読み込んだものをループする

Posted at

遭遇したケース

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);
}
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2