Ở đây chúng ta sẽ xem cách tạo một trang xuất dữ liệu đơn giản, bằng cách loại bỏ các giao diện mặc định và tạo ra giao diện riêng của chúng ta để quản lý nút xuất dữ liệu.

1 – Thêm thư viện xuất dữ liệu
composer require sonata-project/exporter
Sau đó, chúng ta cần thêm một tệp cấu hình cho công cụ xuất dữ liệu của mình.
#config/packages/sonata_exporter.yml
sonata_exporter:
writers:
csv:
delimiter: ";"
2 – Tạo bộ điều khiển của chúng ta
Chúng ta sẽ tạo bộ điều khiển của mình, chứa cấu hình cơ bản.
<?php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface as RoutingUrlGeneratorInterface;
use Sonata\FormatterBundle\Form\Type\SimpleFormatterType;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\RouteCollection;
class ExportModuleAdmin extends AbstractAdmin
{
public function __construct( $code, $class, $baseControllerName ) {
parent::__construct( $code, $class, $baseControllerName );
}
public function configure()
{
parent::configure();
}
}
Sau đó chúng ta cần tạo các hành động:
Chúng ta xóa tất cả các tuyến đường, tạo một tuyến đường export-module cho trang của mình.
protected function configureRoutes(RouteCollection $collection)
{
$collection->clearExcept(['export-module']);
$collection->remove('create');
$collection->add('export-module');
}
Sau đó, chúng ta cần đăng ký giao diện của mình trong các dịch vụ
admin.export:
class: App\Admin\ExportModuleAdmin
arguments: [~, App\Entity\Export, App\Admin\CustomAction]
tags:
- { name: sonata.admin, manager_type: orm, label: "Export CSV" , label_translator_strategy: sonata.admin.label.strategy.underscore, label_catalogue: default}
public: true
Như bạn có thể thấy, đối số thứ ba của chúng ta là một bộ điều khiển quản trị bổ sung, sẽ quản lý các hành động của chúng ta (src/Admin/CustomAction.php).
Và chính trong hành động đó chúng ta sẽ định nghĩa giao diện mà chúng ta sẽ sử dụng để thêm nút của mình.
Vì vậy, chúng ta tạo phương thức exportModuleAction() chứa tham chiếu đến mẫu của mình.
<?php
namespace App\Admin;
use Sonata\AdminBundle\Controller\CRUDController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Doctrine\ORM\Query\ResultSetMappingBuilder;
use Doctrine\ORM\Query\ResultSetMapping;
class CustomAction extends CRUDController
{
public function exportDelefAction(){
return $this->renderWithExtraParams('Admin/export.html.twig', array(
'action' => 'export',
'elements' => $this->admin->getShow(),
), null);
}
}
Và tệp twig của chúng ta, nằm trong hệ thống phân cấp templates/Admin/export.html.twig, chứa mã của mình, rất đơn giản, với một liên kết để truy xuất xuất dữ liệu.
Liên kết chỉ là tuyến đường xuất dữ liệu của một giao diện quản trị CRUD chứa đối số định dạng mong muốn (csv).
Chức năng xuất dữ liệu là một chức năng tự động của các giao diện CRUD.
{% extends '@SonataAdmin/standard_layout.html.twig' %}
{% block sonata_admin_content %}
{% include 'SonataCoreBundle:FlashMessage:render.html.twig' %}
<div>
<h2 class="title-border">Export CSV</h2>
<div class="box box-primary">
<div class="box-body">
<ul class="menu list-unstyled mb-0">
<li><a class="btn-link" href="{{ path('admin_app_wdeclar_export', {'format' : 'csv'}) }}">Cliquez ici pour télécharger le fichier csv</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
Để hành động của chúng ta trực tiếp khả dụng từ bảng điều khiển, chúng ta cần đăng ký hành động trong tệp sonata_admin.yml
Và để kiểm tra tuyến đường mà chúng ta sẽ cung cấp, chúng ta chỉ cần sử dụng lệnh:
php bin/console debug:router
Một khi đã xác định, chúng ta sử dụng nó làm URL truy cập cho nút xuất dữ liệu của mình trong menu.
#config/packages/sonata_admin.yaml
sonata_admin:
title: 'Sonata Admin'
dashboard:
blocks:
- { type: sonata.admin.block.admin_list, position: left }
groups:
delef.admin.group.contrats:
label: Gestion des contrats
icon: '<i class="fa fa-cogs "></i>'
items:
- route: admin_app_export_export-module
label: "Export CSV"
Nhưng đó không phải là tất cả. Chúng ta cũng cần cấu hình nút của mình trên bảng điều khiển. Chúng ta sẽ thêm phương thức getDashboardActions().
Chúng ta thêm hành động của mình và lớp CSS của biểu tượng mà chúng ta muốn sử dụng. Ở đây chúng ta sử dụng biểu tượng Font Awesome 5 mà chúng ta đã thêm vào dự án của mình.
public function getDashboardActions()
{
$actions = parent::getDashboardActions();
$actions['import'] = [
'label' => 'Export',
'url' => $this->generateUrl('export-delef'),
'icon' => ' fas fa-file-export',
'translation_domain' => 'SonataAdminBundle', // optional
'template' => '@SonataAdmin/CRUD/dashboard__action.html.twig', // optional
];
return $actions;
}
Điều này mang lại cho chúng ta tệp PHP sau:
<?php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface as RoutingUrlGeneratorInterface;
use Sonata\FormatterBundle\Form\Type\SimpleFormatterType;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Route\RouteCollection;
class ExportModuleAdmin extends AbstractAdmin
{
public function __construct( $code, $class, $baseControllerName ) {
parent::__construct( $code, $class, $baseControllerName );
}
public function configure()
{
parent::configure();
}
protected function configureRoutes(RouteCollection $collection)
{
//$collection->clearExcept(['list']);
$collection->clearExcept(['export-delef']);
$collection->remove('create');
$collection->add('export-delef');
}
public function setContainer(ContainerInterface $container)
{
$this->container = $container;
}
public function getDashboardActions()
{
$actions = parent::getDashboardActions();
$actions['import'] = [
'label' => 'Export',
'url' => $this->generateUrl('export-delef'),
'icon' => ' fas fa-file-export',
'translation_domain' => 'SonataAdminBundle', // optional
'template' => '@SonataAdmin/CRUD/dashboard__action.html.twig', // optional
];
return $actions;
}
}
Ở giai đoạn này, chúng ta có truy cập từ bảng điều khiển:

Và trang tải xuống của chúng ta:

3 – Cấu hình xuất dữ liệu
Chúng ta chỉ thiếu cấu hình xuất dữ liệu.
Chúng ta đã thấy trước đó rằng chúng ta tham chiếu đến một hành động 'xuất dữ liệu' mặc định của một giao diện CRUD của quản trị viên của mình.
Vì vậy, chính trong thực thể của mình chúng ta sẽ cấu hình xuất dữ liệu.
Trong CRUD của mình, chúng ta thêm tham chiếu sau:
use App\Source\DBALStatementSourceIterator;
Và hai phương thức sau:
public function getDataSourceIterator()
{
$container = $this->getConfigurationPool()->getContainer();
$em = $container->get('doctrine.orm.entity_manager');
$conn = $em->getConnection();
$fields = $this->getExportFields();
$field_str = implode(',', $fields);
$sql = "SELECT {$field_str} FROM myTable d where champs1 ='valeur' order by id asc";
$stmt = $conn->prepare($sql);
$stmt->execute();
return new DBALStatementSourceIterator($stmt);
}
public function getExportFields() {
return [
'd.champs1','d.champs2','d.champs3'
];
}
Chúng ta chỉ cần thêm nguồn lặp lại của mình, nằm trong src/Source/DBALStatementSourceIterator.php
<?php
namespace App\Source;
use Sonata\Exporter\Exception\InvalidMethodCallException;
use Sonata\Exporter\Source\SourceIteratorInterface;
class DBALStatementSourceIterator implements SourceIteratorInterface
{
/**
* @var \Doctrine\DBAL\Statement
*/
protected $statement;
/**
* @var mixed
*/
protected $current;
/**
* @var int
*/
protected $position;
/**
* @var bool
*/
protected $rewinded;
/**
* @param \Doctrine\DBAL\Statement $statement
*/
public function __construct(\Doctrine\DBAL\Statement $statement)
{
$this->statement = $statement;
$this->position = 0;
$this->rewinded = false;
}
/**
* {@inheritdoc}
*/
public function current()
{
return $this->current;
}
/**
* {@inheritdoc}
*/
public function next()
{
$this->current = $this->statement->fetch(\Doctrine\DBAL\FetchMode::ASSOCIATIVE);
++$this->position;
}
/**
* {@inheritdoc}
*/
public function key()
{
return $this->position;
}
/**
* {@inheritdoc}
*/
public function valid()
{
return \is_array($this->current);
}
/**
* {@inheritdoc}
*/
public function rewind()
{
if ($this->rewinded) {
throw new InvalidMethodCallException('Cannot rewind a PDOStatement');
}
$this->current = $this->statement->fetch(\Doctrine\DBAL\FetchMode::ASSOCIATIVE);
$this->rewinded = true;
}
}
Và đó là tất cả!