ヘッダー、フッター、複数ページのドキュメント
1 ページで足りることはめったにありません。このチュートリアルでは、自動的に 3 ページへと成長するドキュメントを作成します。さらに、すべてのページに繰り返し表示されるヘッダーと、ページ番号を表示するフッターを追加します。
作成するもの
「作成するもの」という見出しのセクション1 つのスクリプト 01-multipage.php を作成します。これは 3 ページの旅行記を PDF
(Portable Document Format) ファイルとして生成します。
- 旅行記のエントリーは、ページからページへと自動的に流れていきます。ページの終わりを指定することはなく、エンジンが判断します。
- ヘッダー は、すべてのページで繰り返される、ページ上部の帯です。ここではドキュメントのタイトルを表示します。
- フッター は、それと対になる下部の帯です。ここではページ番号を
1 / 3、2 / 3、3 / 3のように表示します。
すべては nextpdf/core パッケージだけで動作します。フォントファイルも、追加の拡張機能も、ネットワークも必要ありません。
ステップ 1: 3 ページの旅行記を作成する
「ステップ 1: 3 ページの旅行記を作成する」という見出しのセクションこのスクリプトでは、2 つのアイデアがすべての処理を担います。
1 つ目は 自動改ページ です。エンジンはテキストを書き込みながら、カーソル、つまり次の行が配置されるページ上の位置を追跡します。setAutoPageBreak(true, margin: 25) は、エンジンにそのカーソルを監視するよう指示します。カーソルが下端から 25 ポイント(およそ 3 分の 1 インチ)以内に近づくと、エンジンはそのページを閉じ、新しいページを開始します。
2 つ目は、ページの装飾要素(page furniture)、すなわちヘッダーとフッターです。これらは最初のページの前に一度だけ記述します。setHeaderData() は、上部の帯に表示するタイトルと短い説明を記録します。フォントとマージンの呼び出しは、文字と、ページ端からの距離を指定します。エンジンはその後、自身が追加するページも含め、作成するすべてのページにこの装飾を描画します。
プロジェクトフォルダーに 01-multipage.php を作成します。
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
// Make sure the output folder exists next to this script.@mkdir(__DIR__ . '/out');
$document = Document::createStandalone();$document->setTitle('NextPDF Travel Journal');
// Configure the header and footer BEFORE the first page.// The engine repeats them on every page for you.$document->setHeaderData(title: 'NextPDF Travel Journal', description: 'A multi-page tutorial document');$document->setHeaderFont('helvetica', 10);$document->setHeaderMargin(5);$document->setFooterFont('helvetica', 8);$document->setFooterMargin(10);
// Turn on automatic page breaks. When the text cursor gets within// 25 points of the bottom edge, the engine starts a new page.$document->setAutoPageBreak(true, margin: 25);
$document->addPage();
$document->setFont('helvetica', 'B', 18);$document->cell(0, 12, 'Travel journal: three days on the coast', newLine: true);$document->ln(5);
$days = [ 1 => 'We followed the shoreline north and counted seventeen lighthouses.', 2 => 'Rain moved in before noon, so we sketched the harbor from a cafe window.', 3 => 'On the last morning the fog lifted and the whole bay turned silver.',];
foreach ($days as $day => $highlight) { $document->setFont('helvetica', 'B', 14); $document->cell(0, 10, "Day {$day}", newLine: true);
$document->setFont('helvetica', '', 11); for ($entry = 1; $entry <= 12; $entry++) { $text = "Entry {$entry} of day {$day}. {$highlight} " . 'The trail hugged the cliffs for most of the afternoon, and every ' . 'turn opened another view of the water. We stopped often to take ' . 'notes, compare maps, and argue happily about where to eat dinner. ' . 'By the time we reached the guesthouse, our boots were soaked and ' . 'our notebooks were full.'; $document->multiCell(0, 7, $text); $document->ln(3); } $document->ln(5);}
// Ask the engine how many pages the layout produced, then save.$pages = $document->getNumPages();$document->save(__DIR__ . '/out/travel-journal.pdf');
echo "Wrote out/travel-journal.pdf with {$pages} pages\n";php 01-multipage.php で実行します。スクリプトは 1 行を出力します。
Wrote out/travel-journal.pdf with 3 pagesout/travel-journal.pdf を開き、スクロールして確認してください。タイトルの帯が 3
ページすべての上部に表示され、ページ番号が右下でカウントアップしていきます。
何が起こったのか
「何が起こったのか」という見出しのセクション書き込みループはページについて一切言及していません。各日の見出しは cell() で書き込まれ、これは 1 行を目に見えないボックスに配置します。エントリーは multiCell()
で書き込まれ、これは長いテキストを必要なだけの行数に折り返します。36 件のエントリーは 1 ページに収まらないため、自動改ページが 2 回発生します。こうして、旅行記はちょうど 3 ページになります。
ヘッダーとフッターは、最初の addPage() 呼び出しよりも前に設定されました。この順序は重要です。すでに描画されたページは、後から更新されません。装飾要素を先に設定すれば、すべてのページが一貫した仕上がりになります。
ページ番号を自分で描画することはありませんでした。フッターはデフォルトでこれを出力します。選んだのは、そのフォントとページ端からの距離だけです。エンジンがページを書き込んでいる間は、最終的なページ数をまだ知ることができません。そのため、各フッターにプレースホルダーを残しておき、保存時に本当の合計数を埋め込みます。
2 つの小さな詳細がスクリプトを仕上げます。@mkdir は out フォルダーを作成し、
@ 記号は、フォルダーがすでに存在する場合に PHP のエラー出力を抑制します。
getNumPages() は、レイアウトが生成したページ数をエンジンに問い合わせるため、最後のメッセージで実際のページ数を報告できます。
うまくいかない場合
「うまくいかない場合」という見出しのセクションrequireの行で「failed to open stream」エラーが出る場合、スクリプトがvendor/autoload.phpを見つけられなかったことを意味します。vendor/を含むプロジェクトフォルダー内で実行してください。- すべてが 1 ページに収まってしまい、テキストの末尾が切れていませんか?その場合、自動改ページがオフになっています。
setAutoPageBreak(true, margin: 25)の行を残し、それを書き込みループよりも上に配置してください。 - フォントファミリーのスペルミスは、見つけられなかったフォント名を示す例外をスローします。
helveticaのスペルを確認し、より深いフォントの問題については フォントとタグ付け を参照してください。 - その他の問題については、トラブルシューティングハブ が症状を原因に対応付け、エラーリファレンス がエンジンの一般的な例外と、それぞれからの回復方法を説明します。
次のステップ
「次のステップ」という見出しのセクションこれでドキュメントは任意の長さまで成長でき、それでも完成された見た目を保てます。 次のチュートリアル では、コンテンツを HTML (Hypertext Markup Language) で記述し、エンジンにそれをページへと変換させます。
今回のトピックをより細かく制御したい場合は、2 つのレシピがさらに掘り下げています。
- 複数ページのドキュメントを作成する は、エッジケースを含め、改ページを詳しく解説します。
- 繰り返しのページヘッダーとフッターを追加する は、オフにする方法も含め、すべてのヘッダーとフッターの設定を順に説明します。