Browse Source

coder standards

pull/907/head
Alan Stanley 7 years ago
parent
commit
0517fd181d
  1. 25
      README.md
  2. 2
      css/islandora_fits.css
  3. 36
      islandora_fits.install
  4. 39
      islandora_fits.module
  5. 3
      src/Plugin/Field/FieldFormatter/FitsFormatter.php
  6. 172
      src/Services/XMLTransform.php

25
README.md

@ -9,11 +9,13 @@ Install and enable this module in the usual way
#### Install FITS Webservice
FITS xmls are generated from an easily installed web service.
Get the latest fits.zip and fits.war from https://projects.iq.harvard.edu/fits/downloads
(on my box I had to install a missing zip library with ‘sudo apt-get install php7.1-zip’)
(on my box I had to install a missing zip library with
‘sudo apt-get install php7.1-zip’)
Install following their instructions.
Copy the .war file to your webapps directory and test.
Edit the catalina.properties file on the Drupal server by adding the following two lines to the bottom of the file-
Edit the catalina.properties file on the Drupal server by adding the
following two lines to the bottom of the file-
fits.home=/<path-to-fits>/fits
shared.loader=/<path-to-fits>/fits/lib/*.jar
@ -27,16 +29,23 @@ Restart Tomcat and test with
Get code from https://github.com/roblib/CrayFits and install. This code can live anywhere, including an external server,
but most installations will have it at /var/www/html.
The App runs by entering php bin/console server:start *:8050 in the App root folder.
The server is stopped with php bin/console server:stop. On a production machine you'd probably want to configure an additonal port in Apache.
The App runs by entering php bin/console server:start *:8050 in the App
root folder.
The server is stopped with php bin/console server:stop.
On a production machine you'd probably want to configure an additional
port in Apache.
Note: The location of the fits webserver is stored in the .env file in the root dir of the Symfony app. This will have to be reconfigured if the Fits server is anywhere other than localhost:8080/fits
Note: The location of the fits webserver is stored in the .env file in the
root dir of the Symfony app. This will have to be reconfigured if the Fits
server is anywhere other than localhost:8080/fits
#### Adding FITs requests to the queue
Copy the file `assets/ca.islandora.alpaca.connector.ocr.blueprint.xml` to `/opt/karak/deploy` on your server. There is no need to restart.
Copy the file `assets/ca.islandora.alpaca.connector.ocr.blueprint.xml`
to `/opt/karak/deploy` on your server. There is no need to restart.
#### Adding Checksum to Display
A pseudo field with the computed checksum can be added to Repository Item display. Naviage to `admin/structure/types/manage/islandora_object/display` to enable or disable display of `File Checksum`.
A pseudo field with the computed checksum can be added to Repository Item
display. Navigate to `admin/structure/types/manage/islandora_object/display`
to enable or disable display of `File Checksum`.

2
css/islandora_fits.css

@ -1,9 +1,11 @@
.islandora_fits_table {
width: 50em;
}
.islandora_fits_table_labels {
width: 50%;
}
.islandora_fits_table_values {
width: 50%;
}

36
islandora_fits.install

@ -0,0 +1,36 @@
<?php
/**
* @file
* Install/update hook implementations.
*/
use Drupal\taxonomy\Entity\Term;
use Drupal\field\Entity\FieldConfig;
/**
* Implements hook_install().
*/
function islandora_fits_install() {
$term_name = 'FITS File';
$test_terms = taxonomy_term_load_multiple_by_name($term_name);
if (!$test_terms) {
$term = Term::create([
'parent' => [],
'name' => $term_name,
'vid' => 'islandora_media_use',
'description' => 'Technical Metadata associated with an original media file',
'field_external_uri' => ['uri' => 'https://projects.iq.harvard.edu/fits'],
])->save();
}
// Add xml extension if it doesn't already exist.
$field = FieldConfig::load("media.file.field_media_file");
$fieldSettings = $field->getSettings();
$extensions = $fieldSettings['file_extensions'];
if (!strpos($extensions, 'xml')) {
$fieldSettings['file_extensions'] .= ' xml';
$field->set('settings', $fieldSettings);
}
}

39
islandora_fits.module

@ -5,14 +5,11 @@
* Contains islandora_fits.module.
*/
use Drupal\field\Entity\FieldConfig;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\media\MediaInterface;
use Drupal\taxonomy\Entity\Term;
use Drupal\file\Entity\File;
use Drupal\media\Entity\Media;
/**
* Implements hook_help().
*/
@ -29,31 +26,6 @@ function islandora_fits_help($route_name, RouteMatchInterface $route_match) {
}
}
/**
* Implements hook_install().
*/
function islandora_fits_install() {
$term_name = 'FITS File';
$test_terms = taxonomy_term_load_multiple_by_name($term_name);
if (!$test_terms) {
$term = Term::create(array(
'parent' => [],
'name' => $term_name,
'vid' => 'islandora_media_use',
'description' => 'Technical Metadata associated with an original media file',
'field_external_uri' => ['uri' => 'https://projects.iq.harvard.edu/fits'],
))->save();
}
// Add xml extension if it doesn't already exist;
$field = FieldConfig::load("media.file.field_media_file");
$fieldSettings = $field->getSettings();
$extensions = $fieldSettings['file_extensions'];
if (!strpos($extensions, 'xml')) {
$fieldSettings['file_extensions'] .= ' xml';
$field->set('settings', $fieldSettings);
}
}
/**
* Implements hook_theme().
*/
@ -86,7 +58,8 @@ function islandora_fits_media_presave(MediaInterface $media) {
$has_new = $transformer->check_new($data);
if ($has_new) {
$media->set('field_complete', FALSE);
} else {
}
else {
$transformer->populate_media($data, $media);
}
}
@ -125,12 +98,12 @@ function islandora_fits_media_insert(MediaInterface $media) {
*/
function islandora_fits_entity_extra_field_info() {
$extra = [];
$extra['node']['islandora_object']['display']['islandora_fits_checksum'] = array(
$extra['node']['islandora_object']['display']['islandora_fits_checksum'] = [
'label' => t('File Checksum'),
'description' => t('Checksum as discovered by FITs webservice'),
'weight' => 100,
'visible' => TRUE,
);
];
return $extra;
}
@ -140,6 +113,7 @@ function islandora_fits_entity_extra_field_info() {
function islandora_fits_entity_view(array &$build, $entity, $display, $view_mode) {
$route_match_item = \Drupal::routeMatch()->getParameters()->all();
$current_entity = reset($route_match_item);
if ($entity === $current_entity) {
$medias = \Drupal::entityQuery(
'media')
@ -170,6 +144,3 @@ function islandora_fits_entity_view(array &$build, $entity, $display, $view_mode
}
}
}

3
src/Plugin/Field/FieldFormatter/FitsFormatter.php

@ -10,7 +10,6 @@ use Drupal\file\Entity\File;
use Drupal\Core\Link;
use Drupal\Core\Url;
/**
* Plugin implementation of the 'fits_formatter' formatter.
*
@ -48,7 +47,6 @@ class FitsFormatter extends FormatterBase {
public function settingsSummary() {
$summary = [];
// Implement settings summary.
return $summary;
}
@ -90,4 +88,5 @@ class FitsFormatter extends FormatterBase {
$output['#title'] = $this->t("FITS Metadata");
return \Drupal::service('renderer')->render($output);
}
}

172
src/Services/XMLTransform.php

@ -2,8 +2,11 @@
namespace Drupal\islandora_fits\Services;
Use Drupal\Component\Utility\Xss;
use Drupal\Component\Utility\Xss;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\field\Entity\FieldConfig;
@ -11,16 +14,42 @@ use Drupal\field\Entity\FieldConfig;
* Class XMLTransform.
*/
class XMLTransform extends ServiceProviderBase {
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface
*/
private $renderer;
/**
* The entity manager.
*
* @var \Drupal\Core\Entity\EntityManagerInterface
*/
private $entityManager;
/**
* List of characters to switch.
*
* @var array
*/
private $forbidden;
/**
* The messenger.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
private $messenger;
/**
* Constructs a new XMLTransform object.
* XMLTransform constructor.
*
* @param \Drupal\Core\Render\RendererInterface $renderer
* The renderer.
* @param \Drupal\Core\Entity\EntityManagerInterface $entityManager
* The entity manager.
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
* The messenger.
*/
public function __construct($renderer, $entityManager, $messenger) {
public function __construct(RendererInterface $renderer, EntityManagerInterface $entityManager, MessengerInterface $messenger) {
$this->renderer = $renderer;
$this->entityManager = $entityManager;
$this->messenger = $messenger;
@ -30,56 +59,62 @@ class XMLTransform extends ServiceProviderBase {
/**
* Transforms FITS xml into renderable array.
*
* @param $input_xml
* @return array
* @param string $input_xml
* Xml to be transformed.
*
* @return array|null
* Array of parsed results.
*/
public function transformFits($input_xml) {
$utf8 = mb_detect_encoding($input_xml, 'UTF-8', true);
$utf8 = mb_detect_encoding($input_xml, 'UTF-8', TRUE);
if (!$utf8) {
$input_xml = utf8_encode($input_xml);
}
try {
$xml = new \SimpleXMLElement($input_xml);
} catch (\Exception $e) {
}
catch (\Exception $e) {
$this->messenger->addWarning(t('File does not contain valid xml.'));
return;
}
$xml->registerXPathNamespace('fits', 'http://hul.harvard.edu/ois/xml/ns/fits/fits_output');
$fits_metadata = $this->islandora_fits_child_xpath($xml);
$headers = array(
$fits_metadata = $this->islandoraFitsChildXpath($xml);
$headers = [
'label' => t('Field'),
'value' => t('Value'),
);
];
if (count($fits_metadata) == 0) {
$variables['islandora_fits_table']['empty'] = '';
$variables['islandora_fits_fieldsets']['empty'] = array(
$variables['islandora_fits_fieldsets']['empty'] = [
'#type' => 'markup',
'#markup' => t('No technical metadata found.'),
);
} else {
];
}
else {
foreach ($fits_metadata as $tool_name => $vals_array) {
$variables['islandora_fits_data'][$tool_name] = array();
$variables['islandora_fits_data'][$tool_name] = [];
$rows = &$variables['islandora_fits_data'][$tool_name];
foreach ($vals_array as $field => $val_array) {
if (!array_key_exists($field, $rows) && $field != 'Filepath') {
$rows[$field] = array(
array('data' => Xss::filter($field), 'class' => 'islandora_fits_table_labels'),
);
$rows[$field] = [
['data' => Xss::filter($field), 'class' => 'islandora_fits_table_labels'],
];
foreach ($val_array as $value) {
if (!isset($rows[$field]['value'])) {
$rows[$field]['value'] = array('data' => Xss::filter($value), 'class' => 'islandora_fits_table_values');
} else {
$rows[$field]['value'] = ['data' => Xss::filter($value), 'class' => 'islandora_fits_table_values'];
}
else {
$data = $rows[$field]['value']['data'] .= ' - ' . Xss::filter($value);
$rows[$field]['value'] = array('data' => $data, 'class' => 'islandora_fits_table_values');
$rows[$field]['value'] = ['data' => $data, 'class' => 'islandora_fits_table_values'];
}
}
}
$table_attributes = array('class' => array('islandora_fits_table'));
$table = array(
$table_attributes = ['class' => ['islandora_fits_table']];
$table = [
'header' => $headers,
'rows' => $rows,
'attributes' => $table_attributes,
);
];
$variables['islandora_fits_table'][$tool_name] = $table;
$variables['islandora_fits_fieldsets'][$tool_name] = [
'#theme' => 'table',
@ -105,8 +140,8 @@ class XMLTransform extends ServiceProviderBase {
'#attached' => [
'library' => [
'islandora_fits/islandora_fits',
]
]
],
],
];
return $renderable;
}
@ -122,11 +157,11 @@ class XMLTransform extends ServiceProviderBase {
* @return array
* An array containing key/value pairs of fields and data.
*/
private function islandora_fits_child_xpath($xml) {
private function islandoraFitsChildXpath(SimpleXMLElement $xml) {
$results = $xml->xpath('/*|/*/fits:metadata');
$output = array();
$output = [];
foreach ($results as $result) {
$this->islandora_fits_children($result, $output);
$this->islandoraFitsChildren($result, $output);
}
return $output;
}
@ -140,18 +175,18 @@ class XMLTransform extends ServiceProviderBase {
*
* @param SimpleXMLElement $child
* The current child that we are searching through.
*
* @param array $output
* An array containing key/value pairs of fields and data.
*/
private function islandora_fits_children($child, &$output) {
private function islandoraFitsChildren(SimpleXMLElement $child, array &$output) {
$grandchildren = $child->xpath('*/*');
if (count($grandchildren) > 0) {
foreach ($grandchildren as $grandchild) {
$this->islandora_fits_children($grandchild, $output);
$this->islandoraFitsChildren($grandchild, $output);
}
}
} else {
else {
$text_results = $child->xpath('text()');
$tool_name = FALSE;
if ($text_results) {
@ -163,7 +198,7 @@ class XMLTransform extends ServiceProviderBase {
}
$output_text = trim((string) $text);
if (!empty($output_text)) {
$fits_out = $this->islandora_fits_construct_output($child->getName(), $tool_name);
$fits_out = $this->islandoraFitsContructOutput($child->getName(), $tool_name);
$tool_label = $fits_out['tool'];
$field_label = $fits_out['name'];
// Need to check if the label already exists in our output
@ -172,21 +207,25 @@ class XMLTransform extends ServiceProviderBase {
if (isset($output[$tool_label])) {
if (!array_key_exists($field_label, $output[$tool_label])) {
$output[$tool_label][$field_label][] = $output_text;
} else {
}
else {
if (!in_array($output_text, $output[$tool_label][$field_label])) {
$output[$tool_label][$field_label][] = $output_text;
}
}
} else {
}
else {
$output[$tool_label][$field_label][] = $output_text;
}
} // No tool attribute.
}
// No tool attribute.
else {
if (isset($output['Unknown'][$field_label])) {
if (!in_array($output_text, $output['Unknown'][$field_label])) {
$output['Unknown'][$field_label][] = $output_text;
}
} else {
}
else {
$output['Unknown'][$field_label][] = $output_text;
}
}
@ -207,11 +246,11 @@ class XMLTransform extends ServiceProviderBase {
* @return array
* Constructed node name for output.
*/
private function islandora_fits_construct_output($node_name, $tool_name) {
private function islandoraFitsContructOutput(string $node_name, string $tool_name) {
// Construct an arbitrary string with all capitals in it.
$capitals = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$name_array = str_split($node_name);
$space_position = array();
$space_position = [];
// Check to see which characters are capitals so we can split
// them up for cleaner display.
@ -230,23 +269,28 @@ class XMLTransform extends ServiceProviderBase {
}
$node_name = ucwords($node_name);
return array('name' => $node_name, 'tool' => ucwords($tool_name));
return ['name' => $node_name, 'tool' => ucwords($tool_name)];
}
/**
* Adds fields to content type.
*
* @param $input_xml
* @param string $input_xml
* Input to be transformed.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*
* @return bool
* Fields to be formatted.
*/
public function add_media_fields($input_xml) {
public function addMediaFields(string $input_xml) {
$fields_added = FALSE;
$data = $this->transformFits($input_xml);
$all_fields = [];
foreach ($data['#output'] as $datum) {
$all_fields = array_merge($all_fields, $this->harvest_values($datum));
$all_fields = array_merge($all_fields, $this->harvestValues($datum));
}
$to_process = $this->normalize_names($all_fields);
$to_process = $this->normalizeNames($all_fields);
foreach ($to_process as $field) {
$exists = FieldStorageConfig::loadByName('media', $field['field_name']);
if (!$exists) {
@ -275,14 +319,16 @@ class XMLTransform extends ServiceProviderBase {
/**
* Populates media.
*
* @param $input_xml
* @param $media
* @param string $input_xml
* String to be transformed.
* @param \Drupal\media\MediaInterface $media
* Media to which transformed xml is to be added.
*/
public function populate_media($input_xml, &$media) {
public function populateMedia(string $input_xml, MediaInterface &$media) {
$data = $this->transformFits($input_xml);
$all_fields = [];
foreach ($data['#output'] as $datum) {
$all_fields = array_merge($all_fields, $this->harvest_values($datum));
$all_fields = array_merge($all_fields, $this->harvestValues($datum));
}
$to_add = [];
foreach ($all_fields as $label => $field_value) {
@ -299,10 +345,13 @@ class XMLTransform extends ServiceProviderBase {
/**
* Extracts and labels content.
*
* @param $input
* @param array $input
* Values to be harvested and prepped.
*
* @return array
* Fields prepped for display.
*/
private function harvest_values($input) {
private function harvestValues(array $input) {
$fields = [];
$label = str_replace(' ', '_', $input['title']);
$rows = $input['data']['#rows'];
@ -317,9 +366,12 @@ class XMLTransform extends ServiceProviderBase {
* Create standardized machine name fields.
*
* @param array $names
* Names to be normalized.
*
* @return array
* Normalized names.
*/
private function normalize_names(array $names) {
private function normalizeNames(array $names) {
$normalized_names = [];
foreach ($names as $label => $field_value) {
$lower = strtolower($label);
@ -335,14 +387,23 @@ class XMLTransform extends ServiceProviderBase {
return $normalized_names;
}
public function check_new($input_xml) {
/**
* Checks to see if new fields are required.
*
* @param string $input_xml
* Xml to be checked.
*
* @return bool
* Whether fields havbe been added.
*/
public function checkNew(string $input_xml) {
$fields_added = FALSE;
$data = $this->transformFits($input_xml);
$all_fields = [];
foreach ($data['#output'] as $datum) {
$all_fields = array_merge($all_fields, $this->harvest_values($datum));
$all_fields = array_merge($all_fields, $this->harvestValues($datum));
}
$to_process = $this->normalize_names($all_fields);
$to_process = $this->normalizeNames($all_fields);
foreach ($to_process as $field) {
$bundle_fields = $this->entityManager->getFieldDefinitions('media', 'fits_technical_metadata');
$bundle_keys = array_keys($bundle_fields);
@ -352,4 +413,5 @@ class XMLTransform extends ServiceProviderBase {
}
return $fields_added;
}
}

Loading…
Cancel
Save