在 CakePHP 3.5.13 中,我有一个 Controller 操作,如下所示:
class ReportController extends AppController
{
public function download($id, $format)
{
}
}
Run Code Online (Sandbox Code Playgroud)
我想要做的是将报告 ID 和格式(例如 XLSX、CSV)的参数传递给download
函数,例如/report/download/123/csv
获取报告 123 的数据并将其输出为 CSV。
我在一个数组中包含了我的报告所需的所有数据,$data
. 我想创建单独的模板(.ctp 文件)以将我的数据格式化为每种所需的格式,然后让download()
函数将它们发送到浏览器进行下载。
所以我调整了我的功能如下:
public function download($id, $format)
{
$data = // ... Model data in array format
$filename = '123'; // filename for the download
switch ($format):
case 'csv':
header('Content-type: text/csv');
header('Content-Disposition: attachment; filename="'.$filename.'.csv"');
$this->viewBuilder()->setLayout('ajax');
$this->set('data', $data);
$this->render('download_csv');
break;
endswitch;
}
Run Code Online (Sandbox Code Playgroud)
这正确地呈现了我从Template/Report/download_csv.ctp
. 它也在 ajax 布局中正确呈现($this->viewBuilder()->setLayout('ajax');
意味着它使用Template/Layout/ajax.ctp
并且因此不包含任何“包装器”HTML)。
访问/report/download/123/csv
浏览器时,会发送一个文件,123.csv
其中包含我请求的数据。但是,响应类型text/html
与text/csv
我的控制器操作中指定的类型不同。
这导致文件内容格式错误 - 它像对待 HTML 而不是 CSV 一样对待它。例如,如果我的download_csv.ctp
模板中有以下内容:
"Field 1", "123\n456",
"Field 2", "789"
Run Code Online (Sandbox Code Playgroud)
它按字面意思输出,如 Excel 中所示:
我猜这个问题是由于响应实际上是 HTML 而不是 CSV,但我不确定。
我的问题是是否可以以这种方式使用 .ctp 文件并让它们以指定格式作为下载输出到浏览器?
我知道路由和 URL 扩展还可以完成其他事情,但这个问题与这些无关。我也不想使用插件/扩展。我想知道是否可以使用$this->render()
并让 Cake 渲染一个模板,该模板以请求的格式发送到浏览器以供下载?
调用render()
将简单地呈现给定的模板并使用呈现的数据填充响应正文,而不管响应将发生什么,以及发送的内容类型如何 - 所以答案是肯定的,您可以呈现模板并提供服务它们作为下载。
Excel 没有按照您的预期导入数据,很可能与 CakePHP 没有任何关系,因为 CSV 文件不包含任何内容类型信息。也许您"
在导入文件时选择了错误的文本限定符 ( )。
话虽如此,控制器不应该输出数据,包括标题!在控制器中输出数据会导致各种问题,从在测试环境中无法识别数据,到无法发送标头,甚至数据被截断。相反,使用适当的响应对象方法来相应地准备下载响应,在您的情况下,您正在寻找withType()
and withDownload()
,例如:
case 'csv':
$this->response = $this->response->withType('csv');
$this->response = $this->response->withDownload($filename. '.csv');
$this->viewBuilder()->setLayout('ajax');
$this->set('data', $data);
$this->render('download_csv');
break;
Run Code Online (Sandbox Code Playgroud)
这将添加正确的Content-Type
和Content-Disposition
标题。
也可以看看: