fpdf - going back to the previous page

≯℡__Kan透↙ 提交于 2021-02-18 03:20:53

问题


I am generating pdf invoice using fpdf.

Some invoices containing many items, and details need to go into the second page. However, I need the total, and other details to be displayed on the first page.

Right now, if I can add new page like this: $pdf->AddPage();

But, this puts everything into the second page, whatever after this statement.

There seems to be no way to specify the page for either write or cell methods.

Rendering, and calculations are bit complex, thus don't want to store into a temp array and display after fully rendering the first page.

Thank you.


回答1:


if(!empty($this->replace) && !empty($this->replacement)){
    $this->pages[$n]=str_replace($this->replace,$this->replacement,$this->pages[$n]);
}

I added this code to the fpdf class in _putpages() right under /Page content line 2851

Example after adding above to code:

$pdf->replace = array("{paid_msg}","{balance}");
$pdf->replacement = array("Paid","0.00");

It can be a string or an array.




回答2:


I had a very similar issue and I went ahead and just added the function to the class:

function SetPage($num) {
    $this->page = $num;
}

This does literally what you'd expect. But, when you try to go back to the next page, you need to either set it explicitly or add to the Cell() functionality. Here is where it adds a page:

    if($this->y+$h>$this->PageBreakTrigger && !$this->InHeader && !$this->InFooter && $this->AcceptPageBreak())

This checks for AcceptPageBreak and obviously whether the height of the page is less than where we'll end up if we stay on the page. What I did was add a conditional here to check to see if there WAS another page below. If there was, rather than ADDING a new page, I went ahead and just set my Y to my margin and used the above function to visit that page. As such:

if ($this->page < count($this->pages)) {
        $this->SetPage(($this->page)+1);
        $this->y = .5;
    }

If you're uncomfortable with messing with FPDF, this might not be for you, but my realization after solving this issue was actually that the script was very easily navigated and left a great deal of room for simple improvements. Note that instead of checking above for another page, you could also add a variable that you could call that would temporarily tell the script that instead of adding a page, you just jump to next.




回答3:


FPDF doesn't allow you to go back to a previous page. Once you're done with a page - either by calling AddPage() or by running out of space when SetAutoPageBreak() is turned on - you're done with it.

The workaround is to generate your document without the total, write it to a temporary file then load it back (using FPDI: http://www.setasign.de/products/pdf-php-solutions/fpdi/) and add the total in the correct place.




回答4:


I ran into this issue by having a two-column layout, where one column could be so large it would span to the next page. I wanted to set the Y position back to the same Y position as the first column, so that they are aligned to the top of each other, but also continue the document under the largest of the two columns.

My solution was to record the "Vertical Position" of the document, which includes the Page Number ($pdf->PageNo()) and the Y Position ($pdf->GetY()).

You need to store two different vertical positions. First, store the "Starting point" which is where you will start your second column. Second, store the "Largest point" which is the furthest down the document. The largest point was tricky because you cannot look at page number or Y value alone, you must look at both.

I created these three methods to help me out.

This solution does not include X-position in the example.

public function GetVerticalPosition() {
  // Include page and Y position of the document
  return array(
    'page' => $this->PageNo(),
    'y' => $this->GetY(),
  );
}

public function SetVerticalPosition( $pos ) {
  // Set the page and Y position of the document
  $this->page = $pos['page'];
  $this->SetY( $pos['y'] );
}

public function FurthestVerticalPosition( $aPos, $bPos = null ) {
  if ( $bPos === null ) $bPos = $this->GetVerticalPosition();

  // Returns the "furthest" vertical position between two points, based on page and Y position
  if ( 
    ($aPos['page'] > $bPos['page']) // Furthest position is located on another page
    ||
    ($aPos['page'] == $bPos['page'] && $aPos['y'] > $bPos['y'] ) // Furthest position is within the same page, but further down
  ) {
    return $aPos;
  }else{
    return $bPos;
  }
}

Usage is pretty straightforward. Before you draw your variable-height columns you need to grab the starting position, and start collecting the maximum position.

$startPos = $this->GetVerticalPosition();
$furthestPos = $this->GetVerticalPosition();

After rendering each cell, before rendering another cell on the same level, you want to update the furthest position (if needed), then set back to the starting position.

// Returns the furthest of the two possibilites
$furthestPos = $this->FurthestVerticalPosition( $this->GetVerticalPosition(), $furthestPos );
$this->SetVerticalPosition( $startPos );

When you finish rendering your columns, set the document to the maximum distance that you have recorded so far.

$this->SetVerticalPosition( $furthestPos );

Now your columns are properly aligned, and the document pointer is located immediately after the furthest-drawn column.




回答5:


I had the same issue and I overrode a few methods of the FPDF class and was able to fix it in a fairly simple manner. In order to go back and forth pages, you simply need to change the page attribute of the FPDF object. However, once you go back a page, when you progress to the next page, you'll end up adding a new page instead of progressing to the already existing one. To deal with this issue, I created a boolean called add_new_page, and used it in my rewritten accept_page_break method to see whether or not to create a new page or progress to an already existing one.

def prev_page(self):
    self.page -= 1
    self.add_new_page = False

def next_page(self):
    self.page += 1

def accept_page_break(self):
    "Accept automatic page break or not"
    if self.add_page:
        return self.auto_page_break
    else:
        self.page += 1
        self.add_new_page = True



回答6:


Some clever solutions here, but I don't recommend this trickery, because it goes against the basic FPDF model and will sooner or later probably cause other problems down the road.

Programming is already complex enough!

So, separate the model of the invoice or whatever it is from the presentation. Construct the entire model. Then output the presentation (the PDF in this case).




回答7:


I found very suitable the *str_replace* method, due to the need to write "n of m pages". First wrote the n number normally as I constructed every page and finally replaced the m cipher in $pdf->pages[$i] page by page.




回答8:


Just a simple "hack", but data needs to be ordered by page number (not very difficult^ ^ )

Put in your "for loop" placing data something like :

// ensure we are on the good page, but fields HAVE TO be ordered by page number
while($this->fpdf->PageNo() != $myData->getPage()){
    $this->fpdf->AddPage();
}

And you are done ! No need to alter FPDF :D



来源:https://stackoverflow.com/questions/1609194/fpdf-going-back-to-the-previous-page

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!