Move CSV export action logic to a confirmation form.
This commit is contained in:
parent
60d2357fbc
commit
4e22c5fd83
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* The farmOS Export CSV module.
|
||||
*/
|
||||
|
||||
use Drupal\farm_export_csv\Form\EntityCsvActionForm;
|
||||
use Drupal\farm_export_csv\Routing\EntityCsvActionRouteProvider;
|
||||
|
||||
/**
|
||||
* Implements hook_entity_type_build().
|
||||
*/
|
||||
function farm_export_csv_entity_type_build(array &$entity_types) {
|
||||
/** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
|
||||
|
||||
// Enable the entity CSV export action on assets and logs.
|
||||
foreach (['asset', 'log'] as $entity_type) {
|
||||
if (!empty($entity_types[$entity_type])) {
|
||||
$route_providers = $entity_types[$entity_type]->getRouteProviderClasses();
|
||||
$route_providers['csv'] = EntityCsvActionRouteProvider::class;
|
||||
$entity_types[$entity_type]->setHandlerClass('route_provider', $route_providers);
|
||||
$entity_types[$entity_type]->setLinkTemplate('csv-action-form', '/' . $entity_type . '/csv');
|
||||
$entity_types[$entity_type]->setFormClass('csv-action-form', EntityCsvActionForm::class);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_export_csv\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\File\FileUrlGeneratorInterface;
|
||||
use Drupal\Core\Form\ConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TempStore\PrivateTempStoreFactory;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\file\FileRepositoryInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Provides an entity CSV action form.
|
||||
*
|
||||
* @see \Drupal\farm_export_csv\Plugin\Action\EntityCsv
|
||||
* @see \Drupal\Core\Entity\Form\DeleteMultipleForm
|
||||
*/
|
||||
class EntityCsvActionForm extends ConfirmFormBase {
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\Core\TempStore\SharedTempStore
|
||||
*/
|
||||
protected $tempStore;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The serializer service.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface
|
||||
*/
|
||||
protected $serializer;
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileSystemInterface
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The default file scheme.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultFileScheme;
|
||||
|
||||
/**
|
||||
* The file repository service.
|
||||
*
|
||||
* @var \Drupal\file\FileRepositoryInterface
|
||||
*/
|
||||
protected $fileRepository;
|
||||
|
||||
/**
|
||||
* The file URL generator.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileUrlGeneratorInterface
|
||||
*/
|
||||
protected $fileUrlGenerator;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
/**
|
||||
* The entity type.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeInterface
|
||||
*/
|
||||
protected $entityType;
|
||||
|
||||
/**
|
||||
* The entities to export.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityInterface[]
|
||||
*/
|
||||
protected $entities;
|
||||
|
||||
/**
|
||||
* Constructs an EntityCsvActionForm form object.
|
||||
*
|
||||
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer service.
|
||||
* @param \Drupal\Core\File\FileSystemInterface $file_system
|
||||
* The file system service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\file\FileRepositoryInterface $file_repository
|
||||
* The file repository service.
|
||||
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
|
||||
* The file URL generator.
|
||||
* @param \Drupal\Core\Session\AccountInterface $user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer, FileSystemInterface $file_system, ConfigFactoryInterface $config_factory, FileRepositoryInterface $file_repository, FileUrlGeneratorInterface $file_url_generator, AccountInterface $user) {
|
||||
$this->tempStore = $temp_store_factory->get('entity_csv_confirm');
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->serializer = $serializer;
|
||||
$this->fileSystem = $file_system;
|
||||
$this->defaultFileScheme = $config_factory->get('system.file')->get('default_scheme') ?? 'public';
|
||||
$this->fileRepository = $file_repository;
|
||||
$this->fileUrlGenerator = $file_url_generator;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('tempstore.private'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('serializer'),
|
||||
$container->get('file_system'),
|
||||
$container->get('config.factory'),
|
||||
$container->get('file.repository'),
|
||||
$container->get('file_url_generator'),
|
||||
$container->get('current_user'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
// Get entity type ID from the route because ::buildForm has not yet been
|
||||
// called.
|
||||
$entity_type_id = $this->getRouteMatch()->getParameter('entity_type_id');
|
||||
return $entity_type_id . '_csv_action_confirm_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->formatPlural(count($this->entities), 'Are you sure you want to export a CSV of this @item?', 'Are you sure you want to export a CSV of these @items?', [
|
||||
'@item' => $this->entityType->getSingularLabel(),
|
||||
'@items' => $this->entityType->getPluralLabel(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
if ($this->entityType->hasLinkTemplate('collection')) {
|
||||
return new Url('entity.' . $this->entityType->id() . '.collection');
|
||||
}
|
||||
else {
|
||||
return new Url('<front>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Export');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL) {
|
||||
|
||||
// If we don't have an entity type or list of entities, redirect.
|
||||
$this->entityType = $this->entityTypeManager->getDefinition($entity_type_id);
|
||||
$this->entities = $this->tempStore->get($this->user->id() . ':' . $entity_type_id);
|
||||
if (empty($entity_type_id) || empty($this->entities)) {
|
||||
return new RedirectResponse($this->getCancelUrl()
|
||||
->setAbsolute()
|
||||
->toString());
|
||||
}
|
||||
|
||||
// Delegate to the parent method.
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
|
||||
// Filter out entities the user doesn't have access to.
|
||||
$inaccessible_entities = [];
|
||||
$accessible_entities = [];
|
||||
foreach ($this->entities as $entity) {
|
||||
if (!$entity->access('view', $this->currentUser())) {
|
||||
$inaccessible_entities[] = $entity;
|
||||
continue;
|
||||
}
|
||||
$accessible_entities[] = $entity;
|
||||
}
|
||||
|
||||
// Serialize the entities with the csv format.
|
||||
$output = $this->serializer->serialize($accessible_entities, 'csv');
|
||||
|
||||
// Prepare the file directory.
|
||||
$directory = $this->defaultFileScheme . '://csv';
|
||||
$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
|
||||
|
||||
// Create the file.
|
||||
$filename = 'csv_export-' . date('c') . '.csv';
|
||||
$destination = "$directory/$filename";
|
||||
try {
|
||||
$file = $this->fileRepository->writeData($output, $destination);
|
||||
}
|
||||
|
||||
// If file creation failed, bail with a warning.
|
||||
catch (\Exception $e) {
|
||||
$this->messenger()->addWarning($this->t('Could not create file.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the file temporary.
|
||||
$file->status = 0;
|
||||
$file->save();
|
||||
|
||||
// Add warning message for inaccessible entities.
|
||||
if (!empty($inaccessible_entities)) {
|
||||
$inaccessible_count = count($inaccessible_entities);
|
||||
$this->messenger()->addWarning($this->formatPlural($inaccessible_count, 'Could not export @count @item because you do not have the necessary permissions.', 'Could not export @count @items because you do not have the necessary permissions.', [
|
||||
'@item' => $this->entityType->getSingularLabel(),
|
||||
'@items' => $this->entityType->getPluralLabel(),
|
||||
]));
|
||||
}
|
||||
|
||||
// Add confirmation message.
|
||||
if (count($accessible_entities)) {
|
||||
$this->messenger()->addStatus($this->formatPlural(count($accessible_entities), 'Exported @count @item.', 'Exported @count @items', [
|
||||
'@item' => $this->entityType->getSingularLabel(),
|
||||
'@items' => $this->entityType->getPluralLabel(),
|
||||
]));
|
||||
}
|
||||
|
||||
// Show a link to the file.
|
||||
$url = $this->fileUrlGenerator->generateAbsoluteString($file->getFileUri());
|
||||
$this->messenger()->addMessage($this->t('CSV file created: <a href=":url">%filename</a>', [
|
||||
':url' => $url,
|
||||
'%filename' => $file->label(),
|
||||
]));
|
||||
|
||||
$this->tempStore->delete($this->currentUser()->id() . ':' . $this->entityType->id());
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ class EntityCsvDeriver extends EntityActionDeriverBase {
|
|||
$definition = $base_plugin_definition;
|
||||
$definition['type'] = $entity_type_id;
|
||||
$definition['label'] = $this->t('Export @entity_type CSV', ['@entity_type' => $entity_type->getSingularLabel()]);
|
||||
$definition['confirm_form_route_name'] = 'entity.' . $entity_type->id() . '.csv_form';
|
||||
$definitions[$entity_type_id] = $definition;
|
||||
}
|
||||
$this->derivatives = $definitions;
|
||||
|
|
|
@ -3,14 +3,10 @@
|
|||
namespace Drupal\farm_export_csv\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\Plugin\Action\EntityActionBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\File\FileUrlGeneratorInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\file\FileRepositoryInterface;
|
||||
use Drupal\Core\TempStore\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
/**
|
||||
* Action that exports a CSV file of entities.
|
||||
|
@ -24,39 +20,18 @@ use Symfony\Component\Serializer\SerializerInterface;
|
|||
class EntityCsv extends EntityActionBase {
|
||||
|
||||
/**
|
||||
* The serializer service.
|
||||
* The tempstore object.
|
||||
*
|
||||
* @var \Symfony\Component\Serializer\SerializerInterface
|
||||
* @var \Drupal\Core\TempStore\SharedTempStore
|
||||
*/
|
||||
protected $serializer;
|
||||
protected $tempStore;
|
||||
|
||||
/**
|
||||
* The file system service.
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileSystemInterface
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The default file scheme.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultFileScheme;
|
||||
|
||||
/**
|
||||
* The file repository service.
|
||||
*
|
||||
* @var \Drupal\file\FileRepositoryInterface
|
||||
*/
|
||||
protected $fileRepository;
|
||||
|
||||
/**
|
||||
* The file URL generator.
|
||||
*
|
||||
* @var \Drupal\Core\File\FileUrlGeneratorInterface
|
||||
*/
|
||||
protected $fileUrlGenerator;
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityCsv object.
|
||||
|
@ -69,24 +44,15 @@ class EntityCsv extends EntityActionBase {
|
|||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager service.
|
||||
* @param \Symfony\Component\Serializer\SerializerInterface $serializer
|
||||
* The serializer service.
|
||||
* @param \Drupal\Core\File\FileSystemInterface $file_system
|
||||
* The file system service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory service.
|
||||
* @param \Drupal\file\FileRepositoryInterface $file_repository
|
||||
* The file repository service.
|
||||
* @param \Drupal\Core\File\FileUrlGeneratorInterface $file_url_generator
|
||||
* The file URL generator.
|
||||
* @param \Drupal\Core\TempStore\PrivateTempStoreFactory $temp_store_factory
|
||||
* The tempstore factory.
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* Current user.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer, FileSystemInterface $file_system, ConfigFactoryInterface $config_factory, FileRepositoryInterface $file_repository, FileUrlGeneratorInterface $file_url_generator) {
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager);
|
||||
$this->serializer = $serializer;
|
||||
$this->fileSystem = $file_system;
|
||||
$this->defaultFileScheme = $config_factory->get('system.file')->get('default_scheme') ?? 'public';
|
||||
$this->fileRepository = $file_repository;
|
||||
$this->fileUrlGenerator = $file_url_generator;
|
||||
$this->tempStore = $temp_store_factory->get('entity_csv_confirm');
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,11 +64,8 @@ class EntityCsv extends EntityActionBase {
|
|||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('serializer'),
|
||||
$container->get('file_system'),
|
||||
$container->get('config.factory'),
|
||||
$container->get('file.repository'),
|
||||
$container->get('file_url_generator'),
|
||||
$container->get('tempstore.private'),
|
||||
$container->get('current_user'),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -110,37 +73,8 @@ class EntityCsv extends EntityActionBase {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function executeMultiple(array $entities) {
|
||||
|
||||
// Serialize the entities.
|
||||
$output = $this->serializer->serialize($entities, 'csv');
|
||||
|
||||
// Prepare the file directory.
|
||||
$directory = $this->defaultFileScheme . '://csv';
|
||||
$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY);
|
||||
|
||||
// Create the file.
|
||||
$filename = 'csv_export-' . date('c') . '.csv';
|
||||
$destination = "$directory/$filename";
|
||||
try {
|
||||
$file = $this->fileRepository->writeData($output, $destination);
|
||||
}
|
||||
|
||||
// If file creation failed, bail with a warning.
|
||||
catch (\Exception $e) {
|
||||
$this->messenger()->addWarning($this->t('Could not create file.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make the file temporary.
|
||||
$file->status = 0;
|
||||
$file->save();
|
||||
|
||||
// Show a link to the file.
|
||||
$url = $this->fileUrlGenerator->generateAbsoluteString($file->getFileUri());
|
||||
$this->messenger()->addMessage($this->t('CSV file created: <a href=":url">%filename</a>', [
|
||||
':url' => $url,
|
||||
'%filename' => $file->label(),
|
||||
]));
|
||||
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
|
||||
$this->tempStore->set($this->currentUser->id() . ':' . $this->getPluginDefinition()['type'], $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_export_csv\Routing;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\Routing\EntityRouteProviderInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* Provides routes for the entity CSV export action.
|
||||
*/
|
||||
class EntityCsvActionRouteProvider implements EntityRouteProviderInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRoutes(EntityTypeInterface $entity_type) {
|
||||
$collection = new RouteCollection();
|
||||
$entity_type_id = $entity_type->id();
|
||||
if ($route = $this->getEntityCsvFormRoute($entity_type)) {
|
||||
$collection->add("entity.$entity_type_id.csv_form", $route);
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entity CSV export form route.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
|
||||
* The entity type.
|
||||
*
|
||||
* @return \Symfony\Component\Routing\Route|null
|
||||
* The generated route, if available.
|
||||
*/
|
||||
protected function getEntityCsvFormRoute(EntityTypeInterface $entity_type) {
|
||||
if ($entity_type->hasLinkTemplate('csv-action-form')) {
|
||||
$route = new Route($entity_type->getLinkTemplate('csv-action-form'));
|
||||
$route->setDefault('_form', $entity_type->getFormClass('csv-action-form'));
|
||||
$route->setDefault('entity_type_id', $entity_type->id());
|
||||
$route->setRequirement('_user_is_logged_in', 'TRUE');
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue