From e522639b9936cdc48fcfe2e51c26fe0d06460a1f Mon Sep 17 00:00:00 2001
From: datavoyager <jedimasterkenobi@hotmail.co.uk>
Date: Wed, 5 Apr 2017 20:38:28 +0100
Subject: [PATCH] Add "author data" functionality to SolrDefault (#774)

---
 .../src/VuFind/RecordDriver/SolrDefault.php   | 120 ++++++++++--------
 .../Root/RecordDataFormatterFactory.php       |  24 +++-
 .../SolrDefault/data-authors.phtml            |  43 +++++--
 3 files changed, 121 insertions(+), 66 deletions(-)

diff --git a/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php b/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
index e9ffad89c05..50f95a47c76 100644
--- a/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
+++ b/module/VuFind/src/VuFind/RecordDriver/SolrDefault.php
@@ -250,6 +250,51 @@ class SolrDefault extends AbstractBase
         return null;
     }
 
+    /**
+     * Get Author Information with Associated Data Fields
+     *
+     * @param string $index      The author index [primary, corporate, or secondary]
+     * used to construct a method name for retrieving author data (e.g.
+     * getPrimaryAuthors).
+     * @param array  $dataFields An array of fields to used to construct method
+     * names for retrieving author-related data (e.g., if you pass 'role' the
+     * data method will be similar to getPrimaryAuthorsRoles). This value will also
+     * be used as a key associated with each author in the resulting data array.
+     *
+     * @return array
+     */
+    public function getAuthorDataFields($index, $dataFields = [])
+    {
+        $data = $dataFieldValues = [];
+
+        // Collect author data
+        $authorMethod = sprintf('get%sAuthors', ucfirst($index));
+        $authors = $this->tryMethod($authorMethod, [], []);
+
+        // Collect attribute data
+        foreach ($dataFields as $field) {
+            $fieldMethod = $authorMethod . ucfirst($field) . 's';
+            $dataFieldValues[$field] = $this->tryMethod($fieldMethod, [], []);
+        }
+
+        // Match up author and attribute data (this assumes that the attribute
+        // arrays have the same indices as the author array; i.e. $author[$i]
+        // has $dataFieldValues[$attribute][$i].
+        foreach ($authors as $i => $author) {
+            if (!isset($data[$author])) {
+                $data[$author] = [];
+            }
+
+            foreach ($dataFieldValues as $field => $dataFieldValue) {
+                if (!empty($dataFieldValue[$i])) {
+                    $data[$author][$field][] = $dataFieldValue[$i];
+                }
+            }
+        }
+
+        return $data;
+    }
+
     /**
      * Get award notes for the record.
      *
@@ -428,29 +473,23 @@ class SolrDefault extends AbstractBase
      * Deduplicate author information into associative array with main/corporate/
      * secondary keys.
      *
+     * @param array $dataFields An array of extra data fields to retrieve (see
+     * getAuthorDataFields)
+     *
      * @return array
      */
-    public function getDeduplicatedAuthors()
-    {
-        $authors = [
-            'main' => $this->getAuthorRolesArray(
-                $this->getPrimaryAuthors(),
-                $this->getPrimaryAuthorsRoles()
-            ),
-            'corporate' => $this->getAuthorRolesArray(
-                $this->getCorporateAuthors(),
-                $this->getCorporateAuthorsRoles()
-            ),
-            'secondary' => $this->getAuthorRolesArray(
-                $this->getSecondaryAuthors(),
-                $this->getSecondaryAuthorsRoles()
-            )
-        ];
+    public function getDeduplicatedAuthors($dataFields = ['role'])
+    {
+        $authors = [];
+        foreach (['primary', 'secondary', 'corporate'] as $type) {
+            $authors[$type] = $this->getAuthorDataFields($type, $dataFields);
+        };
 
         // deduplicate
         $dedup = function (&$array1, &$array2) {
             if (!empty($array1) && !empty($array2)) {
-                foreach ($array1 as $author => $roles) {
+                $keys = array_keys($array1);
+                foreach ($keys as $author) {
                     if (isset($array2[$author])) {
                         $array1[$author] = array_merge(
                             $array1[$author],
@@ -462,52 +501,27 @@ class SolrDefault extends AbstractBase
             }
         };
 
-        $dedup($authors['main'], $authors['corporate']);
+        $dedup($authors['primary'], $authors['corporate']);
         $dedup($authors['secondary'], $authors['corporate']);
-        $dedup($authors['main'], $authors['secondary']);
+        $dedup($authors['primary'], $authors['secondary']);
 
-        $dedup_roles = function (&$array) {
-            foreach ($array as $author => $roles) {
-                if (is_array($roles)) {
-                    $array[$author] = array_unique($roles);
+        $dedup_data = function (&$array) {
+            foreach ($array as $author => $data) {
+                foreach ($data as $field => $values) {
+                    if (is_array($values)) {
+                        $array[$author][$field] = array_unique($values);
+                    }
                 }
             }
         };
 
-        $dedup_roles($authors['main']);
-        $dedup_roles($authors['secondary']);
-        $dedup_roles($authors['corporate']);
+        $dedup_data($authors['primary']);
+        $dedup_data($authors['secondary']);
+        $dedup_data($authors['corporate']);
 
         return $authors;
     }
 
-    /**
-     * Helper function to restructure author arrays including relators
-     *
-     * @param array $authors Array of authors
-     * @param array $roles   Array with relators of authors
-     *
-     * @return array
-     */
-    protected function getAuthorRolesArray($authors = [], $roles = [])
-    {
-        $authorRolesArray = [];
-
-        if (!empty($authors)) {
-            foreach ($authors as $index => $author) {
-                if (!isset($authorRolesArray[$author])) {
-                    $authorRolesArray[$author] = [];
-                }
-                if (isset($roles[$index]) && !empty($roles[$index])
-                ) {
-                    $authorRolesArray[$author][] = $roles[$index];
-                }
-            }
-        }
-
-        return $authorRolesArray;
-    }
-
     /**
      * Get the edition of the current record.
      *
diff --git a/module/VuFind/src/VuFind/View/Helper/Root/RecordDataFormatterFactory.php b/module/VuFind/src/VuFind/View/Helper/Root/RecordDataFormatterFactory.php
index 13934824dfc..f2da01a8434 100644
--- a/module/VuFind/src/VuFind/View/Helper/Root/RecordDataFormatterFactory.php
+++ b/module/VuFind/src/VuFind/View/Helper/Root/RecordDataFormatterFactory.php
@@ -198,10 +198,16 @@ class RecordDataFormatterFactory
             [
                 'useCache' => true,
                 'labelFunction' => function ($data) {
-                    return count($data['main']) > 1
+                    return count($data['primary']) > 1
                         ? 'Main Authors' : 'Main Author';
                 },
-                'context' => ['type' => 'main', 'schemaLabel' => 'author'],
+                'context' => [
+                    'type' => 'primary',
+                    'schemaLabel' => 'author',
+                    'requiredDataFields' => [
+                        ['name' => 'role', 'prefix' => 'CreatorRoles::']
+                    ]
+                ]
             ]
         );
         $spec->setTemplateLine(
@@ -212,7 +218,13 @@ class RecordDataFormatterFactory
                     return count($data['corporate']) > 1
                         ? 'Corporate Authors' : 'Corporate Author';
                 },
-                'context' => ['type' => 'corporate', 'schemaLabel' => 'creator'],
+                'context' => [
+                    'type' => 'corporate',
+                    'schemaLabel' => 'creator',
+                    'requiredDataFields' => [
+                        ['name' => 'role', 'prefix' => 'CreatorRoles::']
+                    ]
+                ]
             ]
         );
         $spec->setTemplateLine(
@@ -220,7 +232,11 @@ class RecordDataFormatterFactory
             [
                 'useCache' => true,
                 'context' => [
-                    'type' => 'secondary', 'schemaLabel' => 'contributor'
+                    'type' => 'secondary',
+                    'schemaLabel' => 'contributor',
+                    'requiredDataFields' => [
+                        ['name' => 'role', 'prefix' => 'CreatorRoles::']
+                    ]
                 ],
             ]
         );
diff --git a/themes/bootstrap3/templates/RecordDriver/SolrDefault/data-authors.phtml b/themes/bootstrap3/templates/RecordDriver/SolrDefault/data-authors.phtml
index c63f6c6274e..d5e934703ba 100644
--- a/themes/bootstrap3/templates/RecordDriver/SolrDefault/data-authors.phtml
+++ b/themes/bootstrap3/templates/RecordDriver/SolrDefault/data-authors.phtml
@@ -1,15 +1,40 @@
 <?
-  $formatRoles = function ($roles) {
-    if (count($roles) == 0) {
-      return '';
+$formatProperty = function ($datafield, $name, $label) {
+    if (count($datafield) == 0) {
+        return '';
     }
     $that = $this;
-    $translate = function ($str) use ($that) {
-      return $that->transEsc('CreatorRoles::' . $str);
+    $translate = function ($str) use ($that, $label) {
+        return $that->transEsc($label . $str);
     };
-    return ' (' . implode(', ', array_unique(array_map($translate, $roles))) . ')';
-  };
+    return '<span class="author-property-' . $name . '">(' . implode(', ', array_unique(array_map($translate, $datafield))) . ')</span>';
+};
+$formattedAuthors = [];
 ?>
-<? if (isset($data[$type]) && !empty($data[$type])): ?>
-  <? $i = 0; foreach ($data[$type] as $author => $roles): ?><?=($i++ == 0)?'':', '?><span property="<?=$this->escapeHtml($schemaLabel)?>"><a href="<?=$this->record($this->driver)->getLink('author', $author)?>"><?=$this->escapeHtml($author)?></a><?=$formatRoles($roles)?></span><? endforeach; ?>
+<? if (!empty($data[$type])): ?>
+  <? foreach ($data[$type] as $author => $dataFields): ?>
+    <? ob_start(); ?>
+    <span class="author-data" property="<?=$this->escapeHtml($schemaLabel)?>">
+      <a href="<?=$this->record($this->driver)->getLink('author', $author)?>">
+        <?=$this->escapeHtml($author)?>
+      </a>
+      <?
+        // Display additional data using the appropriate translation prefix
+        // (for example, to render author roles correctly):
+        foreach ($requiredDataFields as $field) {
+            $name = $field['name'];
+            $prefix = isset($field['prefix']) ? $field['prefix'] : '';
+            if (isset($dataFields[$name])) {
+                echo $formatProperty($dataFields[$name], $name, $prefix);
+            }
+        }
+      ?>
+    </span>
+    <?
+      // Strip whitespace before close tags to avoid spaces in front of commas:
+      $formattedAuthors[] = trim(preg_replace('/\s+<\//', '</', ob_get_contents()));
+      ob_end_clean();
+    ?>
+  <? endforeach; ?>
 <? endif; ?>
+<?=implode(', ', $formattedAuthors)?>
-- 
GitLab