Skip to content
Snippets Groups Projects
LibraryDocument.php 13.4 KiB
Newer Older
<?php
/**
 * This file is part of Stud.IP.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * @author      Moritz Strohm <strohm@data-quest.de>
 * @copyright   2020
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
 * @category    Stud.IP
 * @since       4.6
 */

/**
 * This class represents a document from a library.
 */
class LibraryDocument
{
    /**
     * An unique ID of the document.
     */
    public $id = '';


    /**
     * The OPAC ID of the document.
     */
    public $opac_document_id = '';


    /**
     * The link to the document page in the OPAC system.
     */
    public $opac_link = '';


    /**
     * The CSL document type.
     */
    public $type = '';


    /**
     * The CSL datafields.
     */
    public $csl_data = [];


    /**
     * The name of the catalog from which the document has been retrieved.
     */
    public $catalog = '';


    /**
     * Other data that cannot be stored in the $csl_data array.
     */
    public $datafields;


    /**
     * The search parameter that have been used to retrieve this item.
     */
    public $search_params = [];


    /**
     * Generates an ID for the document.
     */
    public function getId()
    {
        if (!$this->id) {
            $this->id = md5(uniqid('LibraryDocument' . $this->getTitle()));
        }
        return $this->id;
    }


    /**
     * Returns the type of the document as string.
     *
     * @returns string The type of the document.
     */
    public function getType($format = 'name'): string
    {
        global $LIBRARY_DOCUMENT_TYPES;

        if ($format === 'name') {
            return $this->type;
        }
        if ($format === 'display_name') {
            $ldt = SimpleCollection::createFromArray($LIBRARY_DOCUMENT_TYPES);
            $found = $ldt->findOneBy('name', $this->type);
            $lang = in_array($_SESSION['_language'], ['de_DE', 'en_GB']) ? $_SESSION['_language'] : 'de_DE';
            if ($found) {
                return $found['display_name'][$lang];
            }
        }

        return '';
    }


    /**
     * Returns the title of the document as string.
     *
     * @param string $format The format of the title.
     *     'short' means that only the title is returned.
     *     'long' means that the author, the year and the title are
     *     concatenated into one string.
     *     'long-comma' means that the author, the title and the year
     *     are concatenated in that order, only separated by a comma.
     *
     * @returns string The title of the document.
     */
    public function getTitle($format = 'short'): string
    {
        if ($format == 'long') {
            $long_title = '';
            if (isset($this->csl_data['issued'], $this->csl_data['author'])) {
                $first_author_last_name = $this->csl_data['author'][0]['family'];
                $year = $this->getIssueDate(true);
                if ($year) {
                    $long_title = sprintf('%1$s (%2$s) - ', $first_author_last_name, $year);
                } else {
                    $long_title = sprintf('%s - ', $first_author_last_name);
                }
            } elseif (isset($this->csl_data['author'])) {
                $first_author_last_name = $this->csl_data['author'][0]['family'];
                $long_title = sprintf('%s - ', $first_author_last_name);
            }
            $long_title .= $this->csl_data['title'] ?? '';
            return $long_title;
        } elseif ($format == 'long-comma') {
            $data = [];
            $first_author_last_name = trim($this->csl_data['author'][0]['family']);
            $year = trim($this->getIssueDate(true));
            if ($first_author_last_name) {
                $data[] = $first_author_last_name;
            }
            $data[] = $this->csl_data['title'] ?? '';
            if ($year) {
                $data[] = $year;
            }
            return implode(', ', $data);
        } else {
            return $this->csl_data['title'] ?? '';
        }
    }


    /**
     * @returns string A list with all author names.
     */
    public function getAuthorNames(): string
    {
        if (empty($this->csl_data['author'])) {
            return '';
        }

        $names = [];
        foreach ($this->csl_data['author'] as $author) {
            $names[] = sprintf('%1$s, %2$s', $author['family'], $author['given']);
        }
        return implode('; ', $names);
    }


    /**
     * Returns a string with the issue date.
     *
     * @param bool $year_only Whether to return only the year of the date (true)
     *     or the whole date (false). Defaults to false.
     *
     * @returns string A string representing the issue date.
     */
    public function getIssueDate($year_only = false): string
    {
        if (!$this->csl_data['issued']) {
            return '';
        }
        if ($year_only) {
            $year = @$this->csl_data['issued']['date-parts'][0][0];
            return $year ?: '';
        }
        return implode('-', $this->csl_data['issued']['date-parts'][0]) ?: '';
    }


    /**
     * @returns string A string with identifiers of the document (ISBN, URL, ...).
     */
    public function getIdentifiers(): string
    {
        $identifiers = [];
        if (!empty($this->csl_data['ISBN'])) {
            $identifiers[] = sprintf(_('ISBN: %s'), $this->csl_data['ISBN']);
        }
        if (!empty($this->csl_data['ISSN'])) {
            $identifiers[] = sprintf(_('ISSN: %s'), $this->csl_data['ISSN']);
        }
        return implode('; ', $identifiers);
    }


    /**
     * Filters the CSL data fields by the document type.
     * Only those CSL fields that are specified in library_config.inc.php for
     * the document type are kept.
     */
    public function filterCslFieldsByType()
    {
        if (!$this->type) {
            return;
        }

        $doc_type_config = null;
        foreach ($GLOBALS['LIBRARY_DOCUMENT_TYPES'] as $doc_config) {
            if ($doc_config['name'] == $this->type) {
                $doc_type_config = $doc_config;
                break;
            }
        }
        if ($doc_type_config == null) {
            return;
        }
        $this->csl_data = array_filter(
            $this->csl_data,
            function ($field) use ($doc_type_config) {
                return in_array($field, $doc_type_config['properties']);
            },
            ARRAY_FILTER_USE_KEY
        );
    }


    /**
     * Converts this LibraryDocument to an associative array.
     *
     * @returns array An associative array containing the data of this
     *     LibraryDocument instance.
     */
    public function toArray(): array
    {
        $data = [
            'id'            => $this->getId(),
            'type'          => $this->getType(),
            'csl_data'      => $this->csl_data,
            'datafields'    => $this->datafields,
            'search_params' => $this->search_params,
            'catalog'       => $this->catalog,
            'opac_link'     => $this->opac_link
        ];
        return $data;
    }


    /**
     * Converts this LibraryDocument to JSON data.
     *
     * @returns string A string containing the JSON encoded version of this
     *     LibraryDocument instance.
     */
    public function toJson(): string
    {
        return json_encode($this->toArray());
    }


    /**
     * Fills or creates empty or missing CSL data fields that may be required
     * when rendering the CSL data.
     *
     * @returns array The "enriched" CSL data from this document.
     */
    public function fillEmptyCslFields(): array
    {
        $enriched_data = [];
        foreach ($this->csl_data as $key => $field) {
            if ($key == 'author') {
                if (!$field[0]['family']) {
                    $field[0]['family'] = ' ';
                }
            }
            $enriched_data[$key] = $field;
        }
        //Make sure all "mandatory" fields are there:
        if (!array_key_exists('author', $enriched_data)) {
            $enriched_data['author'] = [
                [
                    'given'  => '',
                    'family' => ' ',
                    'suffix' => ''
                ]
            ];
        }
        return $enriched_data;
    }


    /**
     * Creates a LibraryDocument instance from an associative array.
     *
     * @param array $data An associative array containing data for
     *     a LibraryDocument instance.
     *
     * @returns LibraryDocument|null A LibraryDocument instance on success
     *     or null on failure.
     */
    public static function createFromArray(array $data = [])
    {
        if (!$data) {
            return null;
        }
        $doc = new LibraryDocument();
        $doc->id = $data['id'];
        $doc->type = $data['type'];
        $doc->csl_data = $data['csl_data'];
        $doc->datafields = $data['datafields'];
        $doc->search_params = $data['search_params'];
Jan-Hendrik Willms's avatar
Jan-Hendrik Willms committed
        $doc->catalog = $data['catalog'] ?? null;
        $doc->opac_link = $data['opac_link'] ?? null;
        return $doc;
    }


    /**
     * Creates a LibraryDocument instance from JSON data.
     *
     * @param string $json_string A JSON string containing data for
     *     a LibraryDocument instance.
     *
     * @returns LibraryDocument|null A LibraryDocument instance on success
     *     or null on failure.
     */
    public static function createFromJson(string $json_string = "")
    {
        if (!$json_string) {
            return null;
        }
        $data = json_decode($json_string);
        if (!$data) {
            return null;
        }
        return self::createFromArray($data);
    }


    /**
     * Determines if this document is equal to another document.
     * Equality is determined by comparing various ID fields
     * and as a last resort, the title, author and year are compared.
     *
     * @param LibraryDocument $other Another library document that shall be
     *     compared to this document.
     *
     * @returns bool True, if this document is equal to the other document,
     *     false otherwise.
     */
    public function isEqualTo(LibraryDocument $other): bool
    {
        if ($this->type != $other->type) {
            //No need to do any further checks.
            return false;
        }
        if ($this->id && ($this->id == $other->id)) {
            return true;
        } elseif ($this->csl_data['ISSN'] && ($this->csl_data['ISSN'] == $other->csl_data['ISSN'])) {
            return true;
        } elseif ($this->csl_data['ISBN'] && ($this->csl_data['ISBN'] == $other->csl_data['ISBN'])) {
            return true;
        } elseif ($this->csl_data['DOI'] && ($this->csl_data['DOI'] == $other->csl_data['DOI'])) {
            return true;
        } elseif ($this->csl_data['title'] && $this->csl_data['author'] && $this->csl_data['issued']
            && ($this->csl_data['title'] == $other->csl_data['title'])
            && ($this->csl_data['author'] == $other->csl_data['author'])
            && ($this->csl_data['issued'] == $other->csl_data['issued'])) {
            return true;
        }
        return false;
    }


    /**
     * @returns Flexi\Template A template containing information about the
     *     the document.
     */
    public function getInfoTemplate($format = 'short')
    {
        $factory = new Flexi\Factory(
            $GLOBALS['STUDIP_BASE_PATH'] . '/templates/library/'
        );
        $template = $factory->open('library_document_info');
        $template->set_attribute('document', $this);
        $template->set_attribute('format', $format);
        return $template;
    }


    /**
     * Creates a descriptive text of the search parameters that lead to the
     * retrieval of this document.
     *
     * @returns string[] An array with a textual representation of all
     *     used search parameters.
     */
    public function getSearchDescription()
    {
        $description = [];
        if (isset($this->search_params[LibrarySearch::AUTHOR])) {
            $description[] = sprintf(_('Autor: „%s“'), $this->search_params[LibrarySearch::AUTHOR]);
        }
        if (isset($this->search_params[LibrarySearch::YEAR])) {
            $description[] = sprintf(_('Jahr: „%s“'), $this->search_params[LibrarySearch::YEAR]);
        }
        if (isset($this->search_params[LibrarySearch::TITLE])) {
            $description[] = sprintf(_('Titel: „%s“'), $this->search_params[LibrarySearch::TITLE]);
        }
        if (isset($this->search_params[LibrarySearch::NUMBER])) {
            $description[] = sprintf(_('Nummer: „%s“'), $this->search_params[LibrarySearch::NUMBER]);
        }
        if (isset($this->search_params[LibrarySearch::PUBLICATION])) {
            $description[] = sprintf(_('Zeitschrift: „%s“'), $this->search_params[LibrarySearch::PUBLICATION]);
        }
        if (isset($this->search_params[LibrarySearch::SIGNATURE])) {
            $description[] = sprintf(_('Signatur: „%s“'), $this->search_params[LibrarySearch::SIGNATURE]);
        }
        return $description;
    }

    public function getIcon()
    {
        global $LIBRARY_DOCUMENT_TYPES;
        $ldt = SimpleCollection::createFromArray($LIBRARY_DOCUMENT_TYPES);
        $found = $ldt->findOneBy('name', $this->type);
        $shape = $found['icon'] ?? 'literature-request';
        return Icon::create($shape);
    }
}