Export dat do CSV, XML, TXT apod

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

Ahoj, nevím, zda se tento dotaz týká přímo Nette, ale i tak se zeptám: Mám stránku, na ní AppForm se dvěma inputy a tlačítko Export. Jak mám udělat, aby se po kliku na Export poslal uživateli daný soubor s exportem dat z formuláře? Nejde mi o to jak dostat data z formu, ale jak takový soubor vytvořit a poslat uživateli.

Díky

Ondřej Mirtes
Člen | 1536
+
0
-

V továrničce na formulář:

$form->addSubmit('export', 'Export')->onClick[] = array($this, 'exportClicked');

A pak metoda:

public function exportClicked($button) {
	$this->terminate(new DownloadResponse('cestaKSouboru.csv'));
}

Cesta k souboru by měla být absolutní, tj. včetně APP_DIR, WWW_DIR či kde ten soubor máš.

Editoval Ondřej Mirtes (29. 1. 2010 16:09)

Vyki
Člen | 388
+
0
-

Pro jednoduchý export je to pěkně ukázáno v distribuci v examples. Vtip je v tom, že se v šabloně nenačte layout pomocí {extends none}. Šablona se pak klasicky nakrmí daty třeba formátu XML, TXT. Pro tyto formáty kdy to chceš zobrazit a né stáhnout je to ideální. \\Edit: ještě dodávám, že v šabloně pro nastavení správné hlavičky lze použít makro {contentType text/xml} (příklad pro export do XML).

Editoval Vyki (29. 1. 2010 16:35)

lumen
Člen | 32
+
0
-

Supr, díky za rady… Ještě mám drobný dotaz tady k tomu:

Ondřej Mirtes napsal(a):

A pak metoda:

public function exportClicked($button) {
	$this->terminate(new DownloadResponse('cestaKSouboru.csv'));
}

Cesta k souboru by měla být absolutní, tj. včetně APP_DIR, WWW_DIR či kde ten soubor máš.

co když nechci vubec pracovat se souborem na úrovni souborového systému na serveru. Jen si chci třeba vygenerovat nějaký string a ten pak v podobě třeba TXT souboru uživateli poslat. Jak na to?

PS: Co přesně provádí funkce terminate() ?

Ondřej Mirtes
Člen | 1536
+
0
-

Tak v takovém případě na to budeš muset jít asi starou skoro-PHP cestou…

(převzato z php.net – při jiném typu souboru bude třeba změnit některé hlavičky)

$filename = 'nazev-souboru.txt';
$file = 'stringKeStazeni';

$response = Environment::getHttpResponse();
$response->setHeader('Content-Description', 'File Transfer');
$response->setContentType('text/plain', 'UTF-8');
$response->setHeader('Content-Disposition', 'attachment; filename=' . $filename);
$response->setHeader('Content-Transfer-Encoding', 'binary');
$response->setHeader('Expires', 0);
$response->setHeader('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
$response->setHeader('Pragma', 'public');
$response->setHeader('Content-Length', strlen($file));

ob_clean();
flush();
echo $file;

$this->terminate();

Metoda Presenter::terminate() – „Correctly terminates Presenter.“ Zkrátka místo nějakého exit() v Nette použiješ $this->terminate(), což zajistí korektní ukončení celého životního cyklu aplikace. Můžeš ji jako parametr předat objekt implementující IPresenterResponse a tím říct, co se má před ukončením vlastně stát/poslat na výstup.

Editoval Ondřej Mirtes (4. 2. 2010 10:08)

lumen
Člen | 32
+
0
-

Děkuju.. přesně to co jsem myslel…

Lopo
Člen | 277
+
0
-

aktualne pouzivam tento sposob:
na stranke je link na action exportXML, v prezenteri obsluha

<?php
	public function handleExportXML()
	{
		$model=new Obchod_XTab;
		$data=$model->getXTab();
		$cols=$model->getCols();

		header('Content-Type: application/vnd.ms-excel');
		header('Content-Disposition: attachment;filename="crosstab.xml"');
		header('Cache-Control: max-age=0');
		$this->setLayout('empty');
		$this->setView('exportXML');
		$this->template->cols=$cols;
		$this->template->data=$data;
	}
?>

kde $cols je zoznam stlpcov, $data su proste data :)

sablona:

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
	<ss:Styles>
		<ss:Style ss:ID="0">
			<ss:Font ss:Bold="1"/>
			<ss:Alignment ss:Horizontal="Center" ss:WrapText="0"/>
			<ss:Interior ss:Color="#B8CCE4" ss:Pattern="Solid"/>
		</ss:Style>
		<ss:Style ss:ID="1">
			<ss:Alignment ss:WrapText="0"/>
			<ss:NumberFormat ss:Format="0"/>
		</ss:Style>
		<ss:Style ss:ID="2">
			<ss:Alignment ss:WrapText="0"/>
			<ss:NumberFormat ss:Format="Fixed"/>
		</ss:Style>
		<ss:Style ss:ID="3">
			<ss:Alignment ss:WrapText="0"/>
		</ss:Style>
	</ss:Styles>
	<ss:Worksheet ss:Name="Sheet1">
		<ss:Table>
			<ss:Row>
				{foreach $cols as $col}
				<ss:Cell ss:StyleID="0"><ss:Data ss:Type="String">{!$col['name']}</ss:Data></ss:Cell>
				{/foreach}
			</ss:Row>
			{foreach $data as $row}
			<ss:Row>
				{foreach $cols as $col}
				<ss:Cell ss:StyleID="{if $col['name']=='cipa' || $col['name']=='voj'}1{elseif $iterator->getCounter()<17}3{else}2{/if}"><ss:Data ss:Type="{if $col['name']=='cipa' || $col['name']=='voj' || $iterator->getCounter()>=17}Number{else}String{/if}">{$row[$col['name']]}</ss:Data></ss:Cell>
				{/foreach}
			</ss:Row>
			{/foreach}
		</ss:Table>
	</ss:Worksheet>
</ss:Workbook>

layout empty je proste prazdny subor @empty.phtml – ale podla predchadzajucich prispevkov to asi presunem do sablony ako extends, podobne aj contenttype hlavicku

v sablone potom je cez if-y prepinanie datovych typov buniek

mam aj trosku upraveny sposob, tam nejdem cez $cols ale len cez data a popisky stlpcov su natvrdo v sablone

tento sposob je bez problemov pouzitelny aj na CSV, tam sa potom pouzije contenttype text/csv, excel je vsak co sa tyka importu csv strasne blby kvoli jeho automatickym urcovaniam datoveho typu buniek a preto som robil XML
tuna ukazany je XML bez problemov otvoritelne v exceli 2k7 a podla informacii od pouzivatelov by malo byt aj v exceli 2k3

PetrP
Člen | 587
+
0
-

lumen napsal(a):

co když nechci vubec pracovat se souborem na úrovni souborového systému na serveru. Jen si chci třeba vygenerovat nějaký string a ten pak v podobě třeba TXT souboru uživateli poslat. Jak na to?

Můžeš poslat jiný response, třeba RenderResponse. (lze poslat i šablonu)