Improve asset and log CSV exports #783
This commit is contained in:
commit
3e891a880d
|
@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- [Recommend running composer update twice #653](https://github.com/farmOS/farmOS/pull/786)
|
||||
- [Edit form UI improvements #770](https://github.com/farmOS/farmOS/pull/770)
|
||||
- [Improve asset and log CSV exports #783](https://github.com/farmOS/farmOS/pull/783)
|
||||
|
||||
## [3.0.1] 2024-01-18
|
||||
|
||||
|
|
|
@ -2,10 +2,24 @@
|
|||
|
||||
## CSV
|
||||
|
||||
All [Asset](/guide/assets), [Log](/guide/logs), and
|
||||
[Quantity](/guide/quantities) lists in farmOS include an "Export CSV" link at
|
||||
the bottom that will generate and download a CSV file. Any sorts or filters
|
||||
that are applied to the list will be represented in the CSV output.
|
||||
All [Asset](/guide/assets) and [Log](/guide/logs) lists in farmOS provide an
|
||||
"Export CSV" action that will generate a CSV of selected records. These include
|
||||
most of the record's information, including columns that are not visible in the
|
||||
list pages themselves.
|
||||
|
||||
[Quantity](/guide/quantities) lists provide an "Export CSV" link at the bottom of the page
|
||||
that serve a similar purpose. These exports include all of the columns that are
|
||||
visible on the Quantity list page, including information about the Quantity
|
||||
itself, as well as some information about the Log records that the Quantity
|
||||
is attached to.
|
||||
|
||||
Any sorts or filters that are applied to the list will be represented in the
|
||||
CSV output.
|
||||
|
||||
**Warning: CSV exports do not include all data.**
|
||||
|
||||
The [farmOS API](/development/api) is the best way to get access to all raw data
|
||||
in a farmOS instance.
|
||||
|
||||
## KML
|
||||
|
||||
|
|
|
@ -56,8 +56,9 @@ function farm_modules() {
|
|||
'farm_lab_test' => t('Lab test logs'),
|
||||
'farm_birth' => t('Birth logs'),
|
||||
'farm_medical' => t('Medical logs'),
|
||||
'farm_export_csv' => t('CSV exporter'),
|
||||
'farm_import_csv' => t('CSV importer'),
|
||||
'farm_kml' => t('KML export features'),
|
||||
'farm_export_kml' => t('KML exporter'),
|
||||
'farm_import_kml' => t('KML asset importer'),
|
||||
'farm_map_mapbox' => t('Mapbox map layers: Satellite, Outdoors'),
|
||||
'farm_api_default_consumer' => t('Default API Consumer'),
|
||||
|
|
|
@ -6,13 +6,10 @@ dependencies:
|
|||
- image.style.thumbnail
|
||||
module:
|
||||
- asset
|
||||
- csv_serialization
|
||||
- farm_group
|
||||
- farm_location
|
||||
- image
|
||||
- options
|
||||
- rest
|
||||
- serialization
|
||||
- state_machine
|
||||
- user
|
||||
id: farm_group_members
|
||||
|
@ -1052,17 +1049,6 @@ display:
|
|||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Displaying @start - @end of @total'
|
||||
display_link:
|
||||
id: display_link
|
||||
table: views
|
||||
field: display_link
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: display_link
|
||||
label: 'Export CSV'
|
||||
empty: false
|
||||
display_id: csv
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
|
@ -1073,61 +1059,6 @@ display:
|
|||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
||||
csv:
|
||||
id: csv
|
||||
display_title: 'CSV export (rest)'
|
||||
display_plugin: rest_export
|
||||
position: 2
|
||||
display_options:
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: serializer
|
||||
options:
|
||||
uses_fields: false
|
||||
formats:
|
||||
csv: csv
|
||||
row:
|
||||
type: data_field
|
||||
options:
|
||||
field_options:
|
||||
asset_bulk_form:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
image_target_id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
name:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
type:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
flag_value:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
status:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
display_description: ''
|
||||
display_extenders: { }
|
||||
path: assets.csv
|
||||
auth:
|
||||
- cookie
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- request_format
|
||||
- url
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page:
|
||||
id: page
|
||||
display_title: 'Group members (page)'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
name: farmOS CSV
|
||||
description: Provides CSV features for farmOS.
|
||||
type: module
|
||||
package: farmOS
|
||||
core_version_requirement: ^10
|
|
@ -0,0 +1,19 @@
|
|||
services:
|
||||
farm_csv.normalizer.content_entity_normalizer:
|
||||
class: Drupal\farm_csv\Normalizer\ContentEntityNormalizer
|
||||
tags:
|
||||
- { name: normalizer, priority: 10 }
|
||||
arguments: ['@entity_type.manager', '@entity_type.repository', '@entity_field.manager']
|
||||
farm_csv.normalizer.text_long_field_item:
|
||||
class: Drupal\farm_csv\Normalizer\TextLongFieldItemNormalizer
|
||||
tags:
|
||||
- { name: normalizer, priority: 10 }
|
||||
farm_csv.normalizer.entity_reference_field_item:
|
||||
class: Drupal\farm_csv\Normalizer\EntityReferenceFieldItemNormalizer
|
||||
tags:
|
||||
- { name: normalizer, priority: 10 }
|
||||
arguments: ['@entity.repository']
|
||||
farm_csv.normalizer.timestamp_item:
|
||||
class: Drupal\farm_csv\Normalizer\TimestampItemNormalizer
|
||||
tags:
|
||||
- { name: normalizer, priority: 10 }
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_csv\Normalizer;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\serialization\Normalizer\ContentEntityNormalizer as CoreContentEntityNormalizer;
|
||||
|
||||
/**
|
||||
* Normalizes farmOS content entities for CSV exports.
|
||||
*/
|
||||
class ContentEntityNormalizer extends CoreContentEntityNormalizer {
|
||||
|
||||
/**
|
||||
* The supported format.
|
||||
*/
|
||||
const FORMAT = 'csv';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($entity, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL {
|
||||
$data = parent::normalize($entity, $format, $context);
|
||||
|
||||
// If columns were explicitly included, remove others.
|
||||
if (!empty($context['include_columns'])) {
|
||||
foreach (array_keys($data) as $key) {
|
||||
if (!in_array($key, $context['include_columns'])) {
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, string $format = NULL, array $context = []): bool {
|
||||
return $data instanceof ContentEntityInterface && $format == static::FORMAT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_csv\Normalizer;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItemInterface;
|
||||
use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer as CoreEntityReferenceFieldItemNormalizer;
|
||||
|
||||
/**
|
||||
* Normalizes entity reference fields for farmOS CSV exports.
|
||||
*/
|
||||
class EntityReferenceFieldItemNormalizer extends CoreEntityReferenceFieldItemNormalizer {
|
||||
|
||||
/**
|
||||
* The supported format.
|
||||
*/
|
||||
const FORMAT = 'csv';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($field_item, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL {
|
||||
|
||||
// Attempt to load the referenced entity.
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
if ($entity = $field_item->get('entity')->getValue()) {
|
||||
|
||||
// Return content entity labels, if desired.
|
||||
if ($entity instanceof ContentEntityInterface && isset($context['content_entity_labels']) && $context['content_entity_labels'] === TRUE) {
|
||||
return $entity->label();
|
||||
}
|
||||
|
||||
// Return config entity IDs, if desired.
|
||||
if ($entity instanceof ConfigEntityInterface && isset($context['config_entity_ids']) && $context['config_entity_ids'] === TRUE) {
|
||||
return $entity->id();
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, delegate to the parent method.
|
||||
return parent::normalize($field_item, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, string $format = NULL, array $context = []): bool {
|
||||
return $data instanceof EntityReferenceItemInterface && $format == static::FORMAT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_csv\Normalizer;
|
||||
|
||||
use Drupal\serialization\Normalizer\FieldItemNormalizer;
|
||||
use Drupal\text\Plugin\Field\FieldType\TextLongItem;
|
||||
|
||||
/**
|
||||
* Normalizes long text fields for farmOS CSV exports.
|
||||
*/
|
||||
class TextLongFieldItemNormalizer extends FieldItemNormalizer {
|
||||
|
||||
/**
|
||||
* The supported format.
|
||||
*/
|
||||
const FORMAT = 'csv';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($field_item, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL {
|
||||
/** @var \Drupal\text\Plugin\Field\FieldType\TextLongItem $field_item */
|
||||
|
||||
// Return processed text, if desired.
|
||||
if (isset($context['processed_text']) && $context['processed_text'] === TRUE) {
|
||||
return $field_item->get('processed')->getValue();
|
||||
}
|
||||
|
||||
// Delegate to the parent method.
|
||||
return parent::normalize($field_item, $format, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supportsNormalization($data, string $format = NULL, array $context = []): bool {
|
||||
return $data instanceof TextLongItem && $format == static::FORMAT;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_csv\Normalizer;
|
||||
|
||||
use Drupal\serialization\Normalizer\TimestampItemNormalizer as CoreTimestampItemNormalizer;
|
||||
|
||||
/**
|
||||
* Normalizes timestamp fields for farmOS CSV exports.
|
||||
*/
|
||||
class TimestampItemNormalizer extends CoreTimestampItemNormalizer {
|
||||
|
||||
/**
|
||||
* The supported format.
|
||||
*/
|
||||
const FORMAT = 'csv';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function normalize($object, $format = NULL, array $context = []): array|string|int|float|bool|\ArrayObject|NULL {
|
||||
$data = parent::normalize($object, $format, $context);
|
||||
|
||||
// Return the RFC3339 formatted date, if desired.
|
||||
if (isset($context['rfc3339_dates']) && $context['rfc3339_dates'] === TRUE) {
|
||||
return $data['value'];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
name: farmOS Export
|
||||
description: Features for exporting records.
|
||||
type: module
|
||||
package: farmOS
|
||||
core_version_requirement: ^10
|
|
@ -0,0 +1,11 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- asset
|
||||
- farm_export_csv
|
||||
id: asset_csv_action
|
||||
label: 'Export CSV'
|
||||
type: asset
|
||||
plugin: entity:csv_action:asset
|
||||
configuration: { }
|
|
@ -0,0 +1,11 @@
|
|||
langcode: en
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- farm_export_csv
|
||||
- log
|
||||
id: log_csv_action
|
||||
label: 'Export CSV'
|
||||
type: log
|
||||
plugin: entity:csv_action:log
|
||||
configuration: { }
|
|
@ -0,0 +1,8 @@
|
|||
name: farmOS Export CSV
|
||||
description: Provides a CSV export action for farmOS.
|
||||
type: module
|
||||
package: farmOS
|
||||
core_version_requirement: ^10
|
||||
dependencies:
|
||||
- farm:farm_export
|
||||
- farm:farm_csv
|
|
@ -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,381 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_export_csv\Form;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\File\FileUrlGeneratorInterface;
|
||||
use Drupal\Core\Form\BaseFormIdInterface;
|
||||
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 implements BaseFormIdInterface {
|
||||
|
||||
/**
|
||||
* The tempstore factory.
|
||||
*
|
||||
* @var \Drupal\Core\TempStore\SharedTempStore
|
||||
*/
|
||||
protected $tempStore;
|
||||
|
||||
/**
|
||||
* The entity type manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The entity field manager.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* 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 \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field 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, EntityFieldManagerInterface $entity_field_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->entityFieldManager = $entity_field_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('entity_field.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 getBaseFormId() {
|
||||
return 'entity_export_csv_action_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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 . '_export_csv_action_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->formatPlural(count($this->entities), 'Export a CSV of @count @item?', 'Export a CSV of @count @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());
|
||||
}
|
||||
|
||||
// Make it clear that CSV exports are limited.
|
||||
$message = $this->t('Note: CSV exports do not include all @item data.', ['@item' => $this->entityType->getSingularLabel()]);
|
||||
$form['warning'] = [
|
||||
'#type' => 'html_tag',
|
||||
'#tag' => 'strong',
|
||||
'#value' => $message,
|
||||
];
|
||||
|
||||
// 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.
|
||||
$context = [
|
||||
|
||||
// Define the columns to include.
|
||||
'include_columns' => $this->getIncludeColumns(),
|
||||
|
||||
// Return processed text from long text fields.
|
||||
'processed_text' => TRUE,
|
||||
|
||||
// Return content entity labels and config entity IDs.
|
||||
'content_entity_labels' => TRUE,
|
||||
'config_entity_ids' => TRUE,
|
||||
|
||||
// Return RFC3339 dates.
|
||||
'rfc3339_dates' => TRUE,
|
||||
];
|
||||
$output = $this->serializer->serialize($accessible_entities, 'csv', $context);
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of columns to include in CSV exports.
|
||||
*
|
||||
* @return string[]
|
||||
* An array of column names.
|
||||
*/
|
||||
protected function getIncludeColumns() {
|
||||
|
||||
// Start with ID and UUID.
|
||||
$columns = [
|
||||
'id',
|
||||
'uuid',
|
||||
];
|
||||
|
||||
// Define which field types are supported.
|
||||
$supported_field_types = [
|
||||
'boolean',
|
||||
'created',
|
||||
'changed',
|
||||
'entity_reference',
|
||||
'list_string',
|
||||
'state',
|
||||
'string',
|
||||
'text_long',
|
||||
'timestamp',
|
||||
];
|
||||
|
||||
// Add base field for supported field types.
|
||||
$base_field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($this->entityType->id());
|
||||
foreach ($base_field_definitions as $field_name => $field_definition) {
|
||||
if (!in_array($field_name, $columns) && in_array($field_definition->getType(), $supported_field_types)) {
|
||||
$columns[] = $field_name;
|
||||
}
|
||||
}
|
||||
|
||||
// Add bundle fields for supported field types.
|
||||
$bundles = $this->entityTypeManager->getStorage($this->entityType->getBundleEntityType())->loadMultiple();
|
||||
foreach ($bundles as $bundle) {
|
||||
if ($this->entityTypeManager->hasHandler($this->entityType->id(), 'bundle_plugin')) {
|
||||
$bundle_fields = $this->entityTypeManager->getHandler($this->entityType->id(), 'bundle_plugin')->getFieldDefinitions($bundle->id());
|
||||
foreach ($bundle_fields as $field_name => $field_definition) {
|
||||
if (!in_array($field_name, $columns) && in_array($field_definition->getType(), $supported_field_types)) {
|
||||
$columns[] = $field_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove revision and language columns.
|
||||
$remove_columns = [
|
||||
'default_langcode',
|
||||
'revision_translation_affected',
|
||||
'revision_created',
|
||||
'revision_user',
|
||||
];
|
||||
$columns = array_filter($columns, function ($name) use ($remove_columns) {
|
||||
return !in_array($name, $remove_columns);
|
||||
});
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_export_csv\Plugin\Action\Derivative;
|
||||
|
||||
use Drupal\Core\Action\Plugin\Action\Derivative\EntityActionDeriverBase;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
||||
/**
|
||||
* Provides an action deriver for the CSV action.
|
||||
*
|
||||
* @see \Drupal\farm_export_csv\Plugin\Action\EntityCsv
|
||||
*/
|
||||
class EntityCsvDeriver extends EntityActionDeriverBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
if (empty($this->derivatives)) {
|
||||
$definitions = [];
|
||||
foreach ($this->getApplicableEntityTypes() as $entity_type_id => $entity_type) {
|
||||
$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;
|
||||
}
|
||||
|
||||
return parent::getDerivativeDefinitions($base_plugin_definition);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function isApplicable(EntityTypeInterface $entity_type) {
|
||||
return in_array($entity_type->id(), ['log', 'asset']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_export_csv\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\Plugin\Action\EntityActionBase;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TempStore\PrivateTempStoreFactory;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Action that exports a CSV file of entities.
|
||||
*
|
||||
* @Action(
|
||||
* id = "entity:csv_action",
|
||||
* action_label = @Translation("Export entity as CSV"),
|
||||
* deriver = "Drupal\farm_export_csv\Plugin\Action\Derivative\EntityCsvDeriver",
|
||||
* )
|
||||
*/
|
||||
class EntityCsv extends EntityActionBase {
|
||||
|
||||
/**
|
||||
* The tempstore object.
|
||||
*
|
||||
* @var \Drupal\Core\TempStore\SharedTempStore
|
||||
*/
|
||||
protected $tempStore;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Constructs a new EntityCsv object.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin ID for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager service.
|
||||
* @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, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager);
|
||||
$this->tempStore = $temp_store_factory->get('entity_csv_confirm');
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('tempstore.private'),
|
||||
$container->get('current_user'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function executeMultiple(array $entities) {
|
||||
/** @var \Drupal\Core\Entity\EntityInterface[] $entities */
|
||||
$this->tempStore->set($this->currentUser->id() . ':' . $this->getPluginDefinition()['type'], $entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($object = NULL) {
|
||||
$this->executeMultiple([$object]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
return $object->access('view', $account, $return_as_object);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@ status: true
|
|||
dependencies:
|
||||
module:
|
||||
- asset
|
||||
- farm_kml
|
||||
- farm_export_kml
|
||||
id: asset_kml_action
|
||||
label: 'Export KML'
|
||||
type: asset
|
|
@ -2,7 +2,7 @@ langcode: en
|
|||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- farm_kml
|
||||
- farm_export_kml
|
||||
- log
|
||||
id: log_kml_action
|
||||
label: 'Export KML'
|
|
@ -0,0 +1,8 @@
|
|||
name: farmOS Export KML
|
||||
description: Provides a KML export action for farmOS.
|
||||
type: module
|
||||
package: farmOS
|
||||
core_version_requirement: ^10
|
||||
dependencies:
|
||||
- farm:farm_export
|
||||
- farm:farm_kml
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_kml\Plugin\Action\Derivative;
|
||||
namespace Drupal\farm_export_kml\Plugin\Action\Derivative;
|
||||
|
||||
use Drupal\Core\Action\Plugin\Action\Derivative\EntityActionDeriverBase;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
|
@ -8,7 +8,7 @@ use Drupal\Core\Entity\EntityTypeInterface;
|
|||
/**
|
||||
* Provides an action deriver for the KML action.
|
||||
*
|
||||
* @see \Drupal\farm_kml\Plugin\Action\EntityKml
|
||||
* @see \Drupal\farm_export_kml\Plugin\Action\EntityKml
|
||||
*/
|
||||
class EntityKmlDeriver extends EntityActionDeriverBase {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\farm_kml\Plugin\Action;
|
||||
namespace Drupal\farm_export_kml\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Action\Plugin\Action\EntityActionBase;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
|
@ -18,7 +18,7 @@ use Symfony\Component\Serializer\SerializerInterface;
|
|||
* @Action(
|
||||
* id = "entity:kml_action",
|
||||
* action_label = @Translation("Export entity geometry as KML"),
|
||||
* deriver = "Drupal\farm_kml\Plugin\Action\Derivative\EntityKmlDeriver",
|
||||
* deriver = "Drupal\farm_export_kml\Plugin\Action\Derivative\EntityKmlDeriver",
|
||||
* )
|
||||
*/
|
||||
class EntityKml extends EntityActionBase {
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Post update functions for farm_kml module.
|
||||
*/
|
||||
|
||||
use Drupal\system\Entity\Action;
|
||||
|
||||
/**
|
||||
* Move KML export actions to new farm_export_kml module.
|
||||
*/
|
||||
function farm_kml_post_update_move_kml_export_actions(&$sandbox = NULL) {
|
||||
|
||||
// Delete the existing KML export action config entities.
|
||||
$configs = Action::loadMultiple(['asset_kml_action', 'log_kml_action']);
|
||||
foreach ($configs as $config) {
|
||||
$config->delete();
|
||||
}
|
||||
|
||||
// Install the farm_export_kml module. This will recreate the actions.
|
||||
if (!\Drupal::service('module_handler')->moduleExists('farm_export_kml')) {
|
||||
\Drupal::service('module_installer')->install(['farm_export_kml']);
|
||||
}
|
||||
}
|
|
@ -6,14 +6,11 @@ dependencies:
|
|||
- system.menu.admin
|
||||
module:
|
||||
- asset
|
||||
- csv_serialization
|
||||
- entity_browser
|
||||
- farm_location
|
||||
- farm_ui_views
|
||||
- image
|
||||
- options
|
||||
- rest
|
||||
- serialization
|
||||
- state_machine
|
||||
- user
|
||||
enforced:
|
||||
|
@ -1155,61 +1152,6 @@ display:
|
|||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
||||
csv:
|
||||
id: csv
|
||||
display_title: 'CSV export (rest)'
|
||||
display_plugin: rest_export
|
||||
position: 7
|
||||
display_options:
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: serializer
|
||||
options:
|
||||
uses_fields: false
|
||||
formats:
|
||||
csv: csv
|
||||
row:
|
||||
type: data_field
|
||||
options:
|
||||
field_options:
|
||||
asset_bulk_form:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
image_target_id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
name:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
type:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
flag_value:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
status:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
display_description: ''
|
||||
display_extenders: { }
|
||||
path: assets.csv
|
||||
auth:
|
||||
- cookie
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- request_format
|
||||
- url
|
||||
- user.permissions
|
||||
tags: { }
|
||||
entity_browser:
|
||||
id: entity_browser
|
||||
display_title: 'Entity browser'
|
||||
|
@ -1693,17 +1635,6 @@ display:
|
|||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Displaying @start - @end of @total'
|
||||
display_link:
|
||||
id: display_link
|
||||
table: views
|
||||
field: display_link
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: display_link
|
||||
label: 'Export CSV'
|
||||
empty: false
|
||||
display_id: csv
|
||||
display_extenders:
|
||||
collapsible_filter:
|
||||
collapsible: true
|
||||
|
@ -2118,17 +2049,6 @@ display:
|
|||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Displaying @start - @end of @total'
|
||||
display_link:
|
||||
id: display_link
|
||||
table: views
|
||||
field: display_link
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: display_link
|
||||
label: 'Export CSV'
|
||||
empty: false
|
||||
display_id: csv
|
||||
display_extenders:
|
||||
collapsible_filter:
|
||||
collapsible: true
|
||||
|
|
|
@ -5,13 +5,10 @@ dependencies:
|
|||
- system.menu.admin
|
||||
- taxonomy.vocabulary.log_category
|
||||
module:
|
||||
- csv_serialization
|
||||
- entity_reference_revisions
|
||||
- farm_ui_views
|
||||
- log
|
||||
- options
|
||||
- rest
|
||||
- serialization
|
||||
- state_machine
|
||||
- taxonomy
|
||||
- user
|
||||
|
@ -2299,71 +2296,6 @@ display:
|
|||
- url.query_args
|
||||
- user.permissions
|
||||
tags: { }
|
||||
csv:
|
||||
id: csv
|
||||
display_title: 'CSV export (rest)'
|
||||
display_plugin: rest_export
|
||||
position: 7
|
||||
display_options:
|
||||
pager:
|
||||
type: none
|
||||
options:
|
||||
offset: 0
|
||||
style:
|
||||
type: serializer
|
||||
options:
|
||||
uses_fields: false
|
||||
formats:
|
||||
csv: csv
|
||||
row:
|
||||
type: data_field
|
||||
options:
|
||||
field_options:
|
||||
log_bulk_form:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
status:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
timestamp:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
name:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
type:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
asset_target_id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
flag_value:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
category_target_id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
owner_target_id:
|
||||
alias: ''
|
||||
raw_output: false
|
||||
display_description: ''
|
||||
display_extenders: { }
|
||||
path: logs.csv
|
||||
auth:
|
||||
- cookie
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
contexts:
|
||||
- 'languages:language_content'
|
||||
- 'languages:language_interface'
|
||||
- request_format
|
||||
- url
|
||||
- user
|
||||
- user.permissions
|
||||
tags: { }
|
||||
page:
|
||||
id: page
|
||||
display_title: 'All logs (page)'
|
||||
|
@ -2384,17 +2316,6 @@ display:
|
|||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Displaying @start - @end of @total'
|
||||
display_link:
|
||||
id: display_link
|
||||
table: views
|
||||
field: display_link
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: display_link
|
||||
label: 'Export CSV'
|
||||
empty: false
|
||||
display_id: csv
|
||||
display_extenders:
|
||||
collapsible_filter:
|
||||
collapsible: true
|
||||
|
@ -2702,17 +2623,6 @@ display:
|
|||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Displaying @start - @end of @total'
|
||||
display_link:
|
||||
id: display_link
|
||||
table: views
|
||||
field: display_link
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: display_link
|
||||
label: 'Export CSV'
|
||||
empty: false
|
||||
display_id: csv
|
||||
display_extenders:
|
||||
collapsible_filter:
|
||||
collapsible: true
|
||||
|
|
|
@ -21,3 +21,12 @@ function farm_ui_views_post_update_enable_collapsible_filter(&$sandbox = NULL) {
|
|||
|
||||
$views_settings->set('display_extenders', $display_extenders)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the farmOS CSV Export module.
|
||||
*/
|
||||
function farm_ui_views_post_update_install_farm_export_csv(&$sandbox) {
|
||||
if (!\Drupal::service('module_handler')->moduleExists('farm_export_csv')) {
|
||||
\Drupal::service('module_installer')->install(['farm_export_csv']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,51 +50,18 @@ class FarmUiViewsTest extends FarmBrowserTestBase {
|
|||
$this->assertSession()->pageTextContains($equipment->label());
|
||||
$this->assertSession()->pageTextContains($water->label());
|
||||
|
||||
// Check that an "Export CSV" link appears on /assets.
|
||||
$this->assertSession()->pageTextContains('Export CSV');
|
||||
|
||||
// Check that the "Export CSV" link includes exposed filters.
|
||||
$this->drupalGet('/assets', ['query' => ['status' => 'active']]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->linkByHrefExists('/assets.csv?status=active');
|
||||
|
||||
// Check that both assets are visible in /assets.csv.
|
||||
$this->drupalGet('/assets.csv');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains($equipment->label());
|
||||
$this->assertSession()->pageTextContains($water->label());
|
||||
|
||||
// Check that only water assets are visible in /assets/water.
|
||||
$this->drupalGet('/assets/water');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains($equipment->label());
|
||||
$this->assertSession()->pageTextContains($water->label());
|
||||
|
||||
// Check that an "Export CSV" link appears on /assets/water, and it
|
||||
// automatically filters by asset type.
|
||||
$this->assertSession()->pageTextContains('Export CSV');
|
||||
$this->assertSession()->linkByHrefExists('/assets.csv?type%5B0%5D=water');
|
||||
|
||||
// Check that only water assets are visible in /assets.csv?type[]=water.
|
||||
$this->drupalGet('/assets.csv', ['query' => ['type' => ['water']]]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextNotContains($equipment->label());
|
||||
$this->assertSession()->pageTextContains($water->label());
|
||||
|
||||
// Check that /assets/equipment includes equipment-specific columns.
|
||||
$this->drupalGet('/assets/equipment');
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Manufacturer');
|
||||
$this->assertSession()->pageTextContains('Model');
|
||||
$this->assertSession()->pageTextContains('Serial number');
|
||||
|
||||
// Check that /assets.csv?type[]=equipment includes equipment-specific
|
||||
// columns.
|
||||
$this->drupalGet('/assets.csv', ['query' => ['type' => ['equipment']]]);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->assertSession()->pageTextContains('Manufacturer');
|
||||
$this->assertSession()->pageTextContains('Model');
|
||||
$this->assertSession()->pageTextContains('Serial number');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue