class KmlImporter in farmOS 2.x
Provides a form for importing KML placemarks as land assets.
@todo Allow placemarks to be imported as any asset type. This is challenging because some asset type bundles have required fields like the "plant type" and "animal type".
Hierarchy
- class \Drupal\Core\Form\FormBase implements ContainerInjectionInterface, FormInterface uses DependencySerializationTrait, LoggerChannelTrait, MessengerTrait, RedirectDestinationTrait, StringTranslationTrait
- class \Drupal\farm_import_kml\Form\KmlImporter
Expanded class hierarchy of KmlImporter
See also
https://www.drupal.org/project/farm/issues/3230970
1 string reference to 'KmlImporter'
- farm_import_kml.routing.yml in modules/
core/ import/ modules/ kml/ farm_import_kml.routing.yml - modules/core/import/modules/kml/farm_import_kml.routing.yml
File
- modules/
core/ import/ modules/ kml/ src/ Form/ KmlImporter.php, line 21
Namespace
Drupal\farm_import_kml\FormView source
class KmlImporter extends FormBase {
/**
* The entity type manager service.
*
* @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;
/**
* Constructs a new KmlImporter object.
*
* @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.
*/
public function __construct(EntityTypeManagerInterface $entity_type_manager, SerializerInterface $serializer, FileSystemInterface $file_system) {
$this->entityTypeManager = $entity_type_manager;
$this->serializer = $serializer;
$this->fileSystem = $file_system;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static($container
->get('entity_type.manager'), $container
->get('serializer'), $container
->get('file_system'));
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'farm_kml_import_import_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form['input'] = [
'#type' => 'details',
'#title' => $this
->t('Input'),
'#open' => TRUE,
];
$form['input']['file'] = [
'#type' => 'managed_file',
'#title' => $this
->t('KML File'),
'#description' => $this
->t('Upload your KML file here and click "Parse".'),
'#upload_location' => 'private://kml',
'#upload_validators' => [
'file_validate_extensions' => 'kml kmz',
],
'#required' => TRUE,
];
$land_type_options = farm_land_type_field_allowed_values();
$form['input']['land_type'] = [
'#type' => 'select',
'#title' => $this
->t('Default land type'),
'#description' => $this
->t('Specify the default land type for the assets in this KML. This can be overridden below on a per-asset basis before creating the assets.'),
'#options' => $land_type_options,
'#required' => TRUE,
];
$form['input']['parse'] = [
'#type' => 'button',
'#value' => $this
->t('Parse'),
'#ajax' => [
'callback' => '::parseKml',
'wrapper' => 'output',
],
];
// Hidden field to track if the file was parsed. This helps with validation.
$form['input']['parsed'] = [
'#type' => 'hidden',
'#value' => FALSE,
];
$form['output'] = [
'#type' => 'container',
'#prefix' => '<div id="output">',
'#suffix' => '</div>',
];
// Only generate the output if a file and land type have been selected.
// Uploading a file will trigger an ajax call, but the land type won't
// be set in the form state until the user selects "Parse".
$file_ids = $form_state
->getValue('file', []);
$land_type = $form_state
->getValue('land_type');
if (empty($file_ids) || empty($land_type)) {
return $form;
}
// Get the uploaded file contents.
/** @var \Drupal\file\FileInterface $file */
$file = $this->entityTypeManager
->getStorage('file')
->load(reset($file_ids));
$path = $file
->getFileUri();
if ($file
->getMimeType() === 'application/vnd.google-earth.kmz' && extension_loaded('zip')) {
$path = 'zip://' . $this->fileSystem
->realpath($path) . '#doc.kml';
}
$data = file_get_contents($path);
// Deserialize the KML placemarks into WKT geometry.
/** @var \Drupal\farm_geo\GeometryWrapper[] $geometries */
$geometries = $this->serializer
->deserialize($data, 'geometry_wrapper', 'geometry_kml');
// Bail if no geometries were found.
if (empty($geometries)) {
$this
->messenger()
->addWarning($this
->t('No placemarks could be parsed from the uploaded file.'));
return $form;
}
// Display the output details.
$form['output']['#type'] = 'details';
$form['output']['#title'] = $this
->t('Output');
$form['output']['#open'] = TRUE;
// Build a tree for asset data.
$form['output']['assets'] = [
'#type' => 'container',
'#tree' => TRUE,
];
foreach ($geometries as $index => $geometry) {
// Create a fieldset for the geometry.
$form['output']['assets'][$index] = [
'#type' => 'fieldset',
'#title' => $this
->t('Geometry') . ' ' . ($index + 1),
];
$form['output']['assets'][$index]['name'] = [
'#type' => 'textfield',
'#title' => $this
->t('Name'),
'#default_value' => $geometry->properties['name'] ?? '',
];
$form['output']['assets'][$index]['land_type'] = [
'#type' => 'select',
'#title' => $this
->t('Land type'),
'#options' => $land_type_options,
'#default_value' => $form_state
->getValue('land_type'),
'#required' => TRUE,
];
$form['output']['assets'][$index]['notes'] = [
'#type' => 'textarea',
'#title' => $this
->t('Notes'),
'#default_value' => $geometry->properties['description'] ?? '',
];
$form['output']['assets'][$index]['geometry'] = [
'#type' => 'textarea',
'#title' => $this
->t('Geometry'),
'#default_value' => $geometry->geometry
->out('wkt'),
];
$form['output']['assets'][$index]['confirm'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Create this asset'),
'#description' => $this
->t('Uncheck this if you do not want to create this asset in farmOS.'),
'#default_value' => TRUE,
];
}
// Mark the form as parsed.
$form['input']['parsed']['#value'] = TRUE;
// Fields for creating a parent asset.
$form['output']['parent'] = [
'#type' => 'container',
'#tree' => TRUE,
];
$form['output']['parent']['create'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Create a parent asset'),
'#description' => $this
->t('Optionally create a parent asset and all geometries above will be added as child assets of it. This is helpful if you are creating a lot of assets, and want to keep them all organized upon import.'),
'#default_value' => FALSE,
];
$form['output']['parent']['name'] = [
'#type' => 'textfield',
'#title' => $this
->t('Name'),
'#states' => [
'visible' => [
':input[name="parent[create]"]' => [
'checked' => TRUE,
],
],
],
];
$form['output']['parent']['land_type'] = [
'#type' => 'select',
'#title' => $this
->t('Land type'),
'#options' => $land_type_options,
'#default_value' => $form_state
->getValue('land_type'),
'#states' => [
'visible' => [
':input[name="parent[create]"]' => [
'checked' => TRUE,
],
],
],
];
$form['output']['submit'] = [
'#type' => 'submit',
'#value' => $this
->t('Create assets'),
];
return $form;
}
/**
* Ajax callback that returns the output fieldset after parsing KML.
*
* @param array $form
* The form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*
* @return mixed
* The elements to replace.
*/
public function parseKml(array &$form, FormStateInterface $form_state) {
return $form['output'];
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Only validate if the file has been parsed.
if (!$form_state
->getValue('parsed')) {
return;
}
$assets = $form_state
->getValue('assets', []);
$confirmed_assets = array_filter($assets, function ($asset) {
return !empty($asset['confirm']);
});
// Set an error if no assets are selected to be created.
if (empty($confirmed_assets)) {
$form_state
->setErrorByName('submit', $this
->t('At least one asset must be created.'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Bail if no file was uploaded.
$file_ids = $form_state
->getValue('file', []);
if (empty($file_ids)) {
$this
->messenger()
->addError($this
->t('File upload failed.'));
return;
}
// Load the assets to create.
$assets = $form_state
->getValue('assets', []);
$confirmed_assets = array_filter($assets, function ($asset) {
return !empty($asset['confirm']);
});
// Create a parent asset if specified.
$parent = $form_state
->getValue('parent');
$parent_asset = NULL;
if (!empty($parent['create'])) {
$parent_asset = Asset::create([
'type' => 'land',
'land_type' => $parent['land_type'],
'is_location' => TRUE,
'is_fixed' => TRUE,
'name' => $parent['name'],
]);
$parent_asset
->save();
$asset_url = $parent_asset
->toUrl()
->setAbsolute()
->toString();
$this
->messenger()
->addMEssage($this
->t('Created land asset: <a href=":url">%asset_label</a>', [
':url' => $asset_url,
'%asset_label' => $parent_asset
->label(),
]));
}
// Create new assets.
foreach ($confirmed_assets as $asset) {
$new_asset = Asset::create([
'type' => 'land',
'land_type' => $asset['land_type'],
'intrinsic_geometry' => $asset['geometry'],
'is_location' => TRUE,
'is_fixed' => TRUE,
]);
// Set the name.
if (!empty($asset['name'])) {
$new_asset
->set('name', $asset['name']);
}
// Set the notes.
if (!empty($asset['notes'])) {
$new_asset
->set('notes', $asset['notes']);
}
// Set the parent.
if (!empty($parent_asset)) {
$new_asset
->set('parent', $parent_asset);
}
$new_asset
->save();
$asset_url = $new_asset
->toUrl()
->setAbsolute()
->toString();
$this
->messenger()
->addMEssage($this
->t('Created land asset: <a href=":url">%asset_label</a>', [
':url' => $asset_url,
'%asset_label' => $new_asset
->label(),
]));
}
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
protected | property | ||
DependencySerializationTrait:: |
public | function | 2 | |
DependencySerializationTrait:: |
public | function | 2 | |
FormBase:: |
protected | property | The config factory. | 3 |
FormBase:: |
protected | property | The request stack. | 1 |
FormBase:: |
protected | property | The route match. | |
FormBase:: |
protected | function | Retrieves a configuration object. | |
FormBase:: |
protected | function | Gets the config factory for this form. | 3 |
FormBase:: |
private | function | Returns the service container. | |
FormBase:: |
protected | function | Gets the current user. | |
FormBase:: |
protected | function | Gets the request object. | |
FormBase:: |
protected | function | Gets the route match. | |
FormBase:: |
protected | function | Gets the logger for a specific channel. | |
FormBase:: |
protected | function | Returns a redirect response object for the specified route. | |
FormBase:: |
public | function | Resets the configuration factory. | |
FormBase:: |
public | function | Sets the config factory for this form. | |
FormBase:: |
public | function | Sets the request stack object to use. | |
KmlImporter:: |
protected | property | The entity type manager service. | |
KmlImporter:: |
protected | property | The file system service. | |
KmlImporter:: |
protected | property | The serializer service. | |
KmlImporter:: |
public | function |
Form constructor. Overrides FormInterface:: |
|
KmlImporter:: |
public static | function |
Instantiates a new instance of this class. Overrides FormBase:: |
|
KmlImporter:: |
public | function |
Returns a unique string identifying the form. Overrides FormInterface:: |
|
KmlImporter:: |
public | function | Ajax callback that returns the output fieldset after parsing KML. | |
KmlImporter:: |
public | function |
Form submission handler. Overrides FormInterface:: |
|
KmlImporter:: |
public | function |
Form validation handler. Overrides FormBase:: |
|
KmlImporter:: |
public | function | Constructs a new KmlImporter object. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 27 |
MessengerTrait:: |
public | function | Gets the messenger. | 27 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |