Zkušenosti s použitím PdfResponse v Nette 2.0b a PHP 5.3

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mr.mac
Člen | 87
+
0
-

Na radu nette guru dávám v plen svoji zkušenost s rozchozením PdfResponse v Nette 2.0 a PHP 5.3 (verze mPDF rovněž 5.3).

PdfResponse má být umístěno v app\libs\PdfResponse\ nebo kdekoli jinde, pak ale musí být cesta umístěna v libsDir – viz ř. 33 PDFResponse.php, kde se uvádí: $mPDFPath = "%libsDir%/PdfResponse/mpdf/mpdf.php".
Jak jsem tedy postupoval?

  1. Provedl jsem úpravy v PDFResponse.php dle doporučení #98 a #100.
  2. V prezenteru, ze kterého chci exportovat do PDF jsem přidal akci:
function actionToPdf($id=0) {
	//šablona pro export do PDF
        $template = $this->createTemplate()->setFile(APP_DIR."/cesta/k/sablone/toPdf.latte");
	//data do šablony
        $model = new Model;
	$item = $model->find($id)->fetch();
	$template->item = $item;
        $pdf = new PDFResponse($template);
        $pdf->documentTitle = "Nadpis: $item->titul";
        $pdf->documentAuthor = "Company name";
        $pdf->mPDF->OpenPrintDialog();
        $this->sendResponse($pdf);
    }

3. Šablona toPdf.latte obsahuje toto:

{extends '../@pdf.layout.latte'}
{block #content}
	{$item->name}
	{$item->adress}
	....

4. Šablona @pdf.layout.latte obsahuje html hlavičku a v body odkaz na {content}, např.:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<meta http-equiv="Content-Language" content="en" />
	<meta name="description" content="MyApplication" />
	<meta n:ifset="$robots" name="robots" content="{$robots}">
	//DŮLEŽITÉ: mPDF standardně používá styl media="print"
	<link rel="stylesheet" media="print" href="{$basePath}/css/print.css" type="text/css">
</head>
<body>
	<div id="content">
		{include #content}
	</div>
</body>
</html>

Takže co bylo pro mě nové je to, že jsem nemohl podstrčit jakoukoli šablonu a myslet si, že cokoli se napoprvé převede do PHP (vč. všech stylů apod.) – havarovalo mi to na drobných chybách ve stylech a html kódu s čím si nette (nebo spíše browser) poradilo „samo“, ale mPDF už ne. Co je DŮLEŽITÉ: mPDF standardně používá styl media=„print“, jak je uvedeno v kódu výše.
Takže to chtělo pěkně „čistý stůl“ – čistou html hlavičku, svoje styly v print.css (např. bez duplicit a různých formátovacích zvěrstev) a ejhle. Výsledek – dokument v PDF vypadá pěkně (barevně i černobíle) bez zbytečností.

EDIT: Tip pro opakování záhlaví tabulek na nové stráce: Z dokumentace mPDF jsem vyčetl toto a funguje to: V šabloně přidat html tagy u definice záhlaví tabulek takto: <table repeat_header="1"> nebo <thead> nebo <tfoot>.

Asi pro vás mnohé, kteří s nette pracujete již delší dobu nic nového, ale možná pro někoho, kdo začíná to k užitku bude.
Díky autorovi, Honzovi Kuchařovi za rady.

Editoval mr.mac (9. 11. 2011 16:08)

kralik
Člen | 230
+
0
-

Ahoj,
prosím nevíš mi poradit.

Zkouším generovat PDF a jednoduché „ahoj svete“ je OK, ale pokud generuji ze šablony dostanu

error: Spojení přerušeno, Spojení se serverem bylo v průběhu načítání stránky ukončeno.

pdf ok:

<?php
//v presenteru
..
	$template = "<b>ahoj světe!</b>";
        $pdf = new \PDFResponse($template);
        $this->sendResponse($pdf);
?>

pdf error:

<?php
//v presenteru
..
	$template = $this->createTemplate()->setFile(APP_DIR."/GastroModule/templates/Static/pdf.latte");
        $pdf = new \PDFResponse($template);
        $this->sendResponse($pdf);
?>

obsah PDFResponse.php

<?php
use Nette\Object,
Nette\Application\IPresenterResponse,
Nette\Callback,
Nette\Environment,
Nette\Utils\Strings,
Nette\Templating\Itemplate;
class PdfResponse extends Object implements Nette\Application\IPresenterResponse {
..
?>

Pokud šablonu pdf.latte otevřu bez * $this->sendResponse($pdf);* tak šablona ok

mooc díky

MartyIX
Člen | 217
+
0
-

Podivej se do logu Apache, tam bys mel videt duvod preruseni spojeni.

kralik
Člen | 230
+
0
-

bohužel jsem v logu nic nenašel.

Obsah logu při pokusu:

<?php
[Wed Dec 21 11:21:36 2011] [notice] Apache/2.2.21 (Win32) PHP/5.3.8 configured -- resuming normal operations
[Wed Dec 21 11:21:36 2011] [notice] Server built: Sep 10 2011 11:34:11
[Wed Dec 21 11:21:36 2011] [notice] Parent: Created child process 3604
[Wed Dec 21 11:21:36 2011] [notice] Child 3604: Child process is running
[Wed Dec 21 11:21:36 2011] [notice] Child 3604: Acquired the start mutex.
[Wed Dec 21 11:21:36 2011] [notice] Child 3604: Starting 64 worker threads.
[Wed Dec 21 11:21:36 2011] [notice] Child 3604: Starting thread to listen on port 80.
[Wed Dec 21 11:21:36 2011] [notice] Child 3604: Starting thread to listen on port 80.

?>

Nic víc

mcmatak
Člen | 490
+
0
-

povedlo se to už někomu portovat do současné verze nette 2 a php 5.3?

knedle
Člen | 34
+
0
-

moje zkušenosti z dneška – tj. NetteFramework-2.0-PHP5.3 – min

1/ upravit PDFResponse.pdf

  • již zmiňováno výše, ale pro jistotu:
<?php
...
use     Nette\Object,
        Nette\Application\IResponse,
        Nette\Callback,
        Nette\Environment,
        Nette\Utils\Strings,
        Nette\Templating\Itemplate;

class PdfResponse extends Object implements IResponse {
...
?>
  • změna fce send() – teda tohle jediné jsem dělal naslepo, možná je to zbytečné a původní send() funguje – prostě nevím
<?php
...
public function send(Nette\Http\IRequest $httpRequest, Nette\Http\IResponse $httpResponse) {
...
?>
  • uvnitř této fce opravit volání webalize
<?php
...
$this->outputName = Strings::webalize($this->documentTitle).".pdf";
...
?>
  • a protože se mi (a už nemám sílu hledat proč) i přes tyto úpravy hlásil ERROR:

Missing item 'libsDir'

na řádku:

<?php
...
$mpdfPath = Environment::expand(self::$mPDFPath);
...
?>

odkomentoval jsem to nastavení natvrdo o 2 řádky výše:

<?php
...
//if(!self::$mPDFPath) {
	self::$mPDFPath = dirname(__FILE__)."/mpdf/mpdf.php";
//}
...
?>

2/ presenter pak prakticky shodný s výše uvedeným:

<?php
...
    public function renderPdf() {

        //šablona pro export do PDF
        $template = $this->createTemplate()->setFile(APP_DIR."/templates/Listek/pdf.latte");
        //data do šablony
        $template->data = $this->section->data;

        $pdf = new \PDFResponse($template);
        $pdf->documentTitle = "Podací lístek České pošty ... 3tecky.cz";
        $pdf->documentAuthor = "@3knedle";
//        $pdf->mPDF->OpenPrintDialog();
        $this->sendResponse($pdf);

    }
...
?>

(teď je to teda render, ale bude to action…)

dále jsem na svém vývojovém localhostu musel zvýšit memory_limit – a to z 128 na 256MB

byl to boj, byl to boj

Editoval knedle (9. 2. 2012 11:03)

TOMeek
Člen | 64
+
0
-

Dneska se s generování PDF peru už od rána. Udělal jsem všechny úpravy, ale zarazím se na chybě Cannot redeclare class mPDF. Laděnka mě odkazuje na řádek 58 v mpdf.php. Verzi jsem testoval 5.3 i 5.4 a pokaždé to skončí stejně. Nevíte co stím?

Edit : Došel jsem na to, že tuto chybu to vyhodí když chci použít latte šablonu. Pokud si $template naplním prostým textem, pdf se generuje bez potíží. Když si šablonu vyrenderuju před uložením do PDF tak se vypíše normálně.

Edit2 : Checkoutnul jsem si aktuální verzi z SVN, podle návodů předělal pro nette2 a PHP 5.3 a už vše jede jak má. Původní PdfResponse u kterého se vyskytovala chyba jsem stáhnul z Gitu

Edit3 : Když už se vtom vrtám, tak jsem zjistil, že v PdfResponse je sice definice na formát papíru (P / L) ale po zadání to nefunguje. Udělal jsem si teda takovou funkcičku

public function pageFormat() {
        return ($this->pageOrientaion == "L") ? $this->pageFormat . '-' . $this->pageOrientaion : $this->pageFormat;
    }

která mi ověří jestli chci papír na šířku a tím mi vrátí buď A4-L nebo jen A4. Pak už jen v mPDFExtended stačí zaměnit $this->pageFormat za $this->pageFormat() a je hotovo. Třebas to někomu někdy pomůže.

Editoval TOMeek (12. 4. 2012 14:27)

Tomáš Votruba
Moderator | 1114
+
0
-

Pokud by se to někomu hodilo (= dělalo velké potíže vlastní rozjetí), podařilo se mi to zprovoznit na Nette 2.0, bez js, který nepoužívám.

Editoval Schmutzka (14. 4. 2012 2:53)

thorn
Člen | 14
+
0
-

@Schmutzka: nehodil by si sem nebo na git i jednoduchy funkcni demicko? moc se mi to nedari rozjet, dekuju

Tomáš Votruba
Moderator | 1114
+
0
-

@thorn: Před pár hodinami jsem aktualizoval, tak se zkus podívat, čekni verzi Nette a stažení mPDF.
S demem se dělat nechci, protože často měním a nechci si přidávat práci.

Napiš rovnou, co máš za chybu, uvidíme.

Editoval Schmutzka (14. 4. 2012 23:46)

thorn
Člen | 14
+
0
-

tak se mi to podarilo rozchodit, ale jen pokud dam ten test(), tak to projde, ale pokud dam save() nebo output(), napriklad:

Presenter:

<?php

use PdfResponse\PdfResponse;

class TstPresenter extends BasePresenter {

    public function renderDefault() {

	$this->setLayout('layout');

	$template = $this->createTemplate()->setFile(APP_DIR . '\templates\tst\pdf.latte');

	$pdf = new PDFResponse($template, $this->context);
	$pdf->documentTitle = "Testovaci dokument";
	//$pdf->test();
	$pdf->save(WWW_DIR . "/generated/");
    }

}

?>

Pohled:

<?php
{block title}
	AIS - test
{/block}

{block content}
	<b>Hello!!!</b>
?>

tak dostanu z ladenky:

<?php

Nette\MemberAccessException

Cannot write to an undeclared property PdfResponse\PdfResponse::$generatedFile.

...

$this->onBeforeComplete($mpdf);
$this->generatedFile = $mpdf; // tu se zastavi

return $this->generatedFile;

?>

Netusis, v cem by mohl byt problem? co mi tam chybi ci tak?

EDIT: verze nette 2.0.3, mPDF je to, co mas v GITu, verze 5.3
EDIT2: tak jsem si s tim chvilku hral, zmenil sem akorat, ze misto $this->generatedFile vracim rovnou $mpdf, vlastne moc nechapu, proc generateFile tam je, pak jsem zakomentoval ten if s $this->generatedFile, to byl jeden problem, pak jsem moc nechapal tomu, ze file_put_contents nevytvori automaticky novou slozku, tak jsem ji teda vytvoril natvrdo a uz to fici jak ma, diky, za tu upravu

Editoval thorn (16. 4. 2012 0:30)

rumcais1
Člen | 80
+
0
-

Použil jsem verzi nette 2.0.8 a zde se už nepoužívají konstanty APP_DIR. A tudíž mi to hází chybu. Nevíte jak to nahradit. Díky.

Šaman
Člen | 2634
+
0
-

Tyto konstanty nebyly nikdy součástí Nette, ale Sandboxu. Nic ti nebrání si je v index.php definovat.
Myslím, že zmizely protože se to bude dnes řešit čistěji přes kontejner pomocí DI.