josegonzalez/cakephp-csvview

此包已被弃用且不再维护。作者建议使用 friendsofcake/cakephp-csvview 包。

CakePHP 的 CSV 视图类

安装量: 184,855

依赖: 0

建议者: 0

安全: 0

星标: 175

关注者: 14

分支: 64

类型:cakephp-plugin

5.0.0 2023-10-13 18:16 UTC

README

CI Coverage Status Total Downloads Latest Stable Version Software License

CsvView 插件

快速启用模型数据的 CSV 输出。

此分支适用于 CakePHP 5.x。详细信息请参阅 版本映射

背景

我需要快速导出数据库中的 CSV 文件。使用视图类手动迭代将会很麻烦,因此我认为使用自定义视图类,如 JsonView 或 XmlView,会更容易。

安装

composer require friendsofcake/cakephp-csvview

启用插件

通过以下命令加载插件:

bin/cake plugin load CsvView

用法

要将扁平数组导出为 CSV,可以编写以下代码:

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['you', 'and', 'me'],
    ];

    $this->set(compact('data'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOption('serialize', 'data');
}

所有要包含在 CSV 中的变量必须在 serialize 视图选项中指定,这与 JsonViewXmlView 的工作方式完全相同。

CSV 输出中可以包含多个变量

public function export()
{
    $data = [['a', 'b', 'c']];
    $data_two = [[1, 2, 3]];
    $data_three = [['you', 'and', 'me']];

    $serialize = ['data', 'data_two', 'data_three'];

    $this->set(compact('data', 'data_two', 'data_three'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOption('serialize', $serialize);
}

如果您希望在 CSV 输出中包含标题或页脚,可以指定 headerfooter 视图选项。两者都是可选的

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['you', 'and', 'me'],
    ];

    $header = ['Column 1', 'Column 2', 'Column 3'];
    $footer = ['Totals', '400', '$3000'];

    $this->set(compact('data'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOptions([
            'serialize' => 'data',
            'header' => $header,
            'footer' => $footer,
        ]);
}

您还可以使用 delimitereolnewlineenclosurebom 分别指定分隔符、换行符、换行、转义字符和字节顺序标记 (BOM) 序列

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['you', 'and', 'me'],
    ];

    $this->set(compact('data'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOptions([
            'serialize' => 'data',
            'delimiter' => chr(9),
            'enclosure' => '"',
            'newline' => '\r\n',
            'eol' => '~',
            'bom' => true,
        ]);
}

这些选项的默认值如下:

  • delimiter: ,
  • enclosure: "
  • newline: \n
  • eol: \n
  • bom: false
  • setSeparator: false

eol 选项用于在输出中生成换行符。然而,newline 是应该替换实际数据中的换行符的字符。建议使用换行符的字符串表示形式以避免生成无效的输出。

一些阅读软件错误地渲染不包含字节顺序标记 (BOM) 字节序列的 UTF-8 编码文件。bom 选项用于在生成的 CSV 输出流的开始处添加字节顺序标记 (BOM) 字节序列。有关更多信息,请参阅 Wikipedia 关于字节顺序标记的文章

可以使用 setSeparator 选项在 CSV 的第一行中显式设置分隔符。某些阅读器需要此才能正确显示 CSV。

如果您有复杂的数据模型,可以使用 extract 视图选项指定每个记录的单独 Hash::extract() 兼容的路径 或可调用

public function export()
{
    $posts = $this->Posts->find();
    $header = ['Post ID', 'Title', 'Created'];
    $extract = [
        'id',
        function (array $row) {
            return $row['title'];
        },
        'created'
    ];

    $this->set(compact('posts'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOptions([
            'serialize' => 'posts',
            'header' => $header,
            'extract' => $extract,
        ]);
}

如果您的数据模型包含一些空值或缺失的键,可以使用 null 选项,就像使用 delimitereolenclosure 一样,来设置在 CSV 中如何显示空值。

null 默认为 ''

自动视图类切换

您可以使用控制器的内容协商功能来自动切换CsvView类,如下所示。

在您的应用中的routes.php文件中,在所需的作用域内启用csv扩展解析,使用$routes->addExtensions(['csv'])

// PostsController.php

// Add the CsvView class for content type negotiation
public function initialize(): void
{
    parent::initialize();

    $this->addViewClasses(['csv' => 'CsvView.Csv']);
}

// Controller action
public function index()
{
    $posts = $this->Posts->find();
    $this->set(compact('posts'));

    if ($this->request->is('csv')) {
        $serialize = 'posts';
        $header = array('Post ID', 'Title', 'Created');
        $extract = array('id', 'title', 'created');

        $this->viewBuilder()->setOptions(compact('serialize', 'header', 'extract'));
    }
}

使用上述控制器,您现在可以访问/posts.csv或使用Accepttext/csv来获取csv格式的数据,使用/posts来获取普通的HTML页面。

对于非常复杂的CSV,您也可以使用自己的视图文件。为此,要么不指定serialize,要么将其设置为null。视图文件将位于当前控制器的csv子目录中。

// View used will be in templates/Posts/csv/export.php
public function export()
{
    $posts = $this->Posts->find();
    $this->set(compact('posts'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOption('serialize', null);
}

设置文件的不同编码

如果您需要csv文件有不同的编码,您必须设置传递给视图的数据的编码以及您想要的csv文件编码。这可以通过使用dataEncodingcsvEncoding来实现。

默认值如下:

  • dataEncoding: UTF-8
  • csvEncoding: UTF-8

** 只有当这两个变量不同时,您的数据才会转换为另一种编码。

CsvView默认使用iconv扩展来编码数据。您可以通过设置transcodingExtension选项来更改用于编码数据的php扩展。

$this->viewBuilder()->setOption('transcodingExtension', 'mbstring');

当前支持的编码扩展如下:

  • iconv
  • mbstring

设置下载的文件名

默认情况下,下载的文件将使用生成它的URL的最后一部分命名。例如:example.com/my-controller/my-action将下载my-action.csv,而example.com/my-controller/my-action/first-param将下载first-param.csv

在IE中,您必须设置文件名,否则它将作为文本文件下载。

要设置自定义文件名,使用Response::withDownload()方法。以下代码片段可以将下载的文件从export.csv更改为my-file.csv

public function export()
{
    $data = [
        ['a', 'b', 'c'],
        [1, 2, 3],
        ['you', 'and', 'me'],
    ];

    $this->setResponse($this->getResponse()->withDownload('my-file.csv'));
    $this->set(compact('data'));
    $this->viewBuilder()
        ->setClassName('CsvView.Csv')
        ->setOption('serialize', 'data');
}

使用特定的视图构建器

在某些情况下,最好不要使用当前控制器的视图构建器$this->viewBuilder(),因为任何对$this->render()的调用都将破坏随后的渲染。

例如,在当前控制器的操作过程中,如果您需要将某些数据作为CSV渲染以简单地将其保存到服务器上的文件中。

不要忘记添加到您的控制器中

use Cake\View\ViewBuilder;

因此,您可以创建一个特定的视图构建器

// Your data array
$data = [];

// Options
$serialize = 'data';
$delimiter = ',';
$enclosure = '"';
$newline = '\r\n';

// Create the builder
$builder = new ViewBuilder();
$builder
    ->setLayout(false)
    ->setClassName('CsvView.Csv')
    ->setOptions(compact('serialize', 'delimiter', 'enclosure', 'newline'));

// Then the view
$view = $builder->build($data);
$view->set(compact('data'));

// And Save the file
file_put_contents('/full/path/to/file.csv', $view->render());