Search code examples
phpfootertcpdftableofcontents

TCPDF Add "Return to Table of Contents" Footer Link


Situation

I'm trying to dynamically generate PDFs from supplied HTML code. I've got the content formatting down, but I'm stuck on trying to get the footer to work correctly. It's a 3-part footer with the author name, page designation, and a "Return to ToC" link, except the link isn't working.

What I've Tried

  1. I am aware of TCPDF How do you make a link to the Table of Contents (TOC)? and have already attempted it's solution, a variation of the link found in the official example 045, without success. I tried just the solution as well as the example, which has the link declared according to the TCPDF_STATIC::$alias_num_page rather than the actual page. Both produced a link with no functionality (not even the mouse icon changes when hovered over, and this is the case for their example file, too).
  2. Mimicking the link creation of the TCPDF::addTOCPage() function. This resulted in functioning links, but they only pointed to the top of the page where the page being clicked was located.
  3. Working with mimicking the link creation of the TCPDF::addTOCPage() function, I realized that the TCPDF::SetLink() function corresponds to the page generated, not the TCPDF_STATIC::$alias_num_page value (final page number value). So, with the ToC being the last page created, it's value should match TCPDF_STATIC::$alias_tot_pages. So, I tried setting the link to that, but it only worked from the ToC. All other pages had the link with no functionality or mouse icon.
  4. I created a new class variable and two functions for setting and getting it's value, but this, again, was worthless due to the variable being set when the ToC page is generated and the links in the footers having been set prior to it's generation, making them all use the default value of "1".

Code

Below is my current version of the MYPDF class detailed in bullet 4.

class MYPDF extends TCPDF {
    protected $tocPageNo = 1;

    public function getTocPageNo() {
        return $this->tocPageNo;
    }

    public function setTocPageNo($num) {
        $this->tocPageNo = is_int($num) ? $num : $this->tocPageNo;
        return;
    }

    public function Footer() {
        if($this->PageNo() !== 1) {
            $this->SetY(-15);
            $this->SetFont('Helvetica', 'I', 8);
            $margins = $this->getMargins();
            $width = ($this->getPageWidth() - $margins['left'] - $margins['right']) / 3;
            $this->MultiCell($width, 0, $GLOBALS['author'], 0, 'L', false, 0);
            $this->MultiCell($width, 0, 'Page ' . $this->getAliasNumPage() . '/' . $this->getAliasNbPages(), 0, 'C', false, 0);
            $link = $this->AddLink();
            $this->SetLink($link, 0, $this->getTocPageNo());
            $this->Write(0, 'Return to Table of Contents', $link, false, 'R');
        }
        return;
    }
}

Note: The use of a global variable is only for basic testing.


Solution

  • Adding a * before the page number should achieve the result you are looking for. Prefixing the page number with the * character will prevent the link from changing when the TOC page is added. This is the change that should be made:

    // $this->SetLink($link, 0, $this->getTocPageNo());
    $this->SetLink($link, 0, '*' . $this->getTocPageNo());
    

    You can read the documentation for this method in the code here on GitHub.

    Also, changing the conditional in the footer will prevent it from printing on the TOC page. In the current configuration, it will skip the first content page. This is the change:

    // if($this->PageNo() !== 1) {
    if (!$this->tocpage) {
    

    Here is a full example:

    <?php
    require_once('tcpdf_include.php');
    
    class MYPDF extends TCPDF {
        public function Footer() {
            if (!$this->tocpage) {
              $this->SetY(-15);
              $this->SetFont('Helvetica', 'I', 8);
              $margins = $this->getMargins();
              $width = ($this->getPageWidth() - $margins['left'] - $margins['right']) / 3;
              $this->MultiCell($width, 0, "Author", 0, 'L', false, 0);
              $this->MultiCell($width, 0, 'Page ' . $this->getAliasNumPage() . '/' . $this->getAliasNbPages(), 0, 'C', false, 0);
              $link = $this->AddLink();
              $this->SetLink($link, 0, '*1');
              $this->Write(0, 'Return to Table of Contents', $link, false, 'R');
            }
            return;
        }
    }
    $pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
    $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
    $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
    $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
    $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
    for ($i = 1; $i < 10; $i++) {
        $pdf->AddPage();
        $pdf->Bookmark('Chapter '.$i, 0, 0, '', 'B', array(0,64,128));
        $pdf->Cell(0, 10, 'Chapter '.$i, 0, 1, 'L');
    }
    $pdf->addTOCPage();
    $pdf->MultiCell(0, 0, 'Table Of Content', 0, 'C', 0, 1, '', '', true, 0);
    $pdf->Ln();
    $pdf->addTOC(1, 'courier', '.', 'INDEX', 'B', array(128,0,0));
    $pdf->endTOCPage();
    $pdf->Output('example.pdf', 'I');