View source
<?php
namespace Drupal\views_oai_pmh\Plugin\views\style;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\style\StylePluginBase;
use Drupal\views\ResultRow;
use Drupal\views_oai_pmh\Plugin\MetadataPrefixInterface;
use Drupal\views_oai_pmh\Plugin\MetadataPrefixManager;
use Drupal\views_oai_pmh\Service\FormatRowToXml;
use Drupal\views_oai_pmh\Service\Repository;
use Drupal\views_oai_pmh\Service\ValueConvertTrait;
use Drupal\views_oai_pmh\Service\Provider;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Serializer\Serializer;
use Picturae\OaiPmh\Implementation\Record as OAIRecord;
use Picturae\OaiPmh\Implementation\Record\Header;
use Picturae\OaiPmh\Implementation\MetadataFormatType;
use Drupal\Core\Cache\Cache;
class Record extends StylePluginBase implements CacheableDependencyInterface {
use ValueConvertTrait;
protected $usesFields = TRUE;
protected $usesOptions = TRUE;
protected $usesRowClass = FALSE;
protected $usesRowPlugin = FALSE;
protected $rowToXml;
protected $prefixManager;
protected $metadataPrefix = [];
protected $serializer;
public $displayHandler;
protected $repository;
protected $provider;
protected $pluginInstances = [];
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('views_oai_pmh.format_row_xml'), $container
->get('plugin.manager.views_oai_pmh_prefix'), $container
->get('serializer'), $container
->get('views_oai_pmh.repository'), $container
->get('views_oai_pmh.provider'));
}
public function __construct(array $configuration, $plugin_id, $plugin_definition, FormatRowToXml $rowToXml, MetadataPrefixManager $prefixManager, Serializer $serializer, Repository $repository, Provider $provider) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->rowToXml = $rowToXml;
$this->prefixManager = $prefixManager;
$this->serializer = $serializer;
$this->repository = $repository;
$this->provider = $provider;
foreach ($prefixManager
->getDefinitions() as $id => $plugin) {
$this->metadataPrefix[$id] = $plugin;
}
}
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);
$handlers = $this->displayHandler
->getHandlers('field');
if (empty($handlers)) {
$form['error_markup'] = [
'#markup' => '<div class="error messages">' . $this
->t('You need at least one field before you can configure your table settings') . '</div>',
];
return;
}
$formats = [];
foreach ($this->metadataPrefix as $prefix_id => $prefix) {
$formats[$prefix_id] = $this
->t($prefix['label']);
}
$form['enabled_formats'] = [
'#type' => 'checkboxes',
'#title' => t('OAI-PMH metadata formats'),
'#description' => t('Select the metadata format(s) that you wish to publish. Note that the Dublin Core format must remain enabled as it is required by the OAI-PMH standard.'),
'#default_value' => $this->options['enabled_formats'],
'#options' => $formats,
];
$form['metadata_prefix'] = [
'#type' => 'fieldset',
'#title' => t('Metadata prefixes'),
];
$field_labels = $this->displayHandler
->getFieldLabels();
foreach ($this->metadataPrefix as $prefix_id => $prefix) {
$form['metadata_prefix'][$prefix_id] = [
'#type' => 'textfield',
'#title' => $prefix['label'],
'#default_value' => $this->options['metadata_prefix'][$prefix_id] ? $this->options['metadata_prefix'][$prefix_id] : $prefix['prefix'],
'#required' => TRUE,
'#size' => 16,
'#maxlength' => 32,
];
$form['field_mappings'][$prefix_id] = [
'#type' => 'fieldset',
'#title' => t('Field mappings for <em>@format</em>', [
'@format' => $prefix['label'],
]),
'#states' => [
'visible' => [
':input[name="style_options[enabled_formats][' . $prefix_id . ']"]' => [
'checked' => TRUE,
],
],
],
];
$prefixPlugin = $this
->getInstancePlugin($prefix_id);
foreach ($this->displayHandler
->getOption('fields') as $field_name => $field) {
$form['field_mappings'][$prefix_id][$field_name] = [
'#type' => 'select',
'#options' => $prefixPlugin
->getElements(),
'#default_value' => !empty($this->options['field_mappings'][$prefix_id][$field_name]) ? $this->options['field_mappings'][$prefix_id][$field_name] : '',
'#title' => $field_labels[$field_name],
];
}
}
}
public function render() {
$rows = $this
->getResultRows();
$currentPrefixPlugin = $this->prefixManager
->createInstance($this->displayHandler
->getCurrentMetadataPrefix());
$records = [];
foreach ($rows as $row_id => $row) {
$this->rowToXml
->resetTagsPrefixedWith0();
$elements = $this->rowToXml
->transform($row);
$element_or_null = array_shift($elements);
$element = $element_or_null ? $element_or_null : array();
$root_elements = $element + $currentPrefixPlugin
->getRootNodeAttributes();
$data = $root_elements + $elements;
$path_id = !empty($data['identifier']) ? $data['identifier']['#'] : $data['dc:identifier']['#'];
$xmlDoc = new \DOMDocument();
$xmlDoc
->loadXML($this->serializer
->encode($data, 'xml', [
'xml_root_node_name' => $currentPrefixPlugin
->getRootNodeName(),
]));
$xpath = new \DOMXPath($xmlDoc);
foreach ($xpath
->query('//*[not(node())]') as $node) {
$node->parentNode
->removeChild($node);
}
$header = new Header($this
->getIdentifier($path_id), new \DateTime());
$records[$row_id] = new OAIRecord($header, $xmlDoc);
}
$formats = [];
foreach ($this->options['enabled_formats'] as $format) {
if ($format) {
$plugin = $this
->getInstancePlugin($format);
$formats[] = new MetadataFormatType($format, $plugin
->getSchema(), $plugin
->getNamespace());
}
}
$this->repository
->setRecords($records);
if ($pager = $this->view->pager
->hasMoreRecords()) {
$this->repository
->setOffset($this->view
->getCurrentPage() + 1);
$this->repository
->setTotalRecords($this->view->total_rows);
}
$this->repository
->setMetadataFormats($formats);
return $this->provider;
}
protected function getIdentifier($id) {
$path = "";
if (strpos($id, 'https://') !== false) {
$path = str_replace("https://", "oai:", $id);
}
else {
if (strpos($id, 'http://') !== false) {
$path = str_replace("http://", "oai:", $id);
}
}
return $path;
}
protected function getResultRows() : array {
$rows = [];
foreach ($this->view->result as $row_id => $row) {
$this->view->row_index = $row_id;
$item = $this
->populateRow($row_id, $row);
$id = $row->_entity
->id();
if (key_exists($id, $rows)) {
$rows[$id] = array_merge_recursive($rows[$id], $item);
}
else {
$rows[$id] = $item;
}
}
return $rows;
}
protected function removeDuplicates($array) {
$output = [];
foreach ($array as $key => $value) {
foreach ($value as $key_i => $value_i) {
$value_old = $value_i[0];
$all_equal = true;
if (is_array($value_i)) {
for ($j = 0; $j < count($value_i); $j++) {
if ($value_i[$j] !== $value_old) {
$all_equal = false;
break;
}
$value_old = $value_i[$j];
}
}
else {
$value_old = $value_i;
}
$delimiter = '';
$key_delimiter = '';
if (strpos($key_i, '>') !== false) {
$delimiter = '>';
$key_delimiter = '@';
}
else {
if (strpos($key_i, 'dc') !== false) {
$delimiter = '@';
}
}
$brothers = $this
->getBrothersKey($key_i, $value, $delimiter, $key_delimiter);
if ($all_equal && empty($brothers)) {
$output[$key][$key_i] = $value_old;
}
else {
if (!$all_equal && empty($brothers)) {
for ($j = 0; $j < count($value_i); $j++) {
if (!in_array($value_i[$j], $output[$key][$key_i])) {
$output[$key][$key_i][] = $value_i[$j];
}
}
}
else {
$tuples = [];
$m = 0;
$nChildren = count($brothers[0][key($brothers[0])]);
for ($k = 0; $k < $nChildren; $k++) {
$tuple = "";
for ($l = 0; $l < count($brothers); $l++) {
if (is_array($brothers[$l][key($brothers[$l])])) {
$tuple = $tuple . $brothers[$l][key($brothers[$l])][$m];
}
else {
$tuple = $tuple . $brothers[$l][key($brothers[$l])];
}
}
if (!in_array($tuple, $tuples)) {
if (is_array($array[$key][$key_i])) {
$output[$key][$key_i][] = $array[$key][$key_i][$m];
}
else {
$output[$key][$key_i][] = $array[$key][$key_i];
}
}
$m++;
$tuples[] = $tuple;
}
}
}
}
}
return $output;
}
public function getBrothersKey($key, $array, $delimiter, $key_delimiter) {
$parts = explode($delimiter, $key);
$sub_key = "";
$output = [];
if ($delimiter === ">") {
if (count($parts) <= 1) {
return $output;
}
if (count($parts) < 3 || strpos($key, $key_delimiter) !== false) {
return $output;
}
for ($i = 0; $i < count($parts) - 1; $i++) {
if ($sub_key === "") {
$sub_key = $parts[$i];
}
else {
$sub_key = $sub_key . $delimiter . $parts[$i];
}
}
}
else {
$sub_key = $parts[0];
}
foreach ($array as $key => $value) {
if (strpos($key, $sub_key) !== false) {
$output[] = [
$key => $value,
];
}
}
if (count($output) === 1) {
$output = [];
}
return $output;
}
protected function populateRow($row_id, ResultRow $row) : array {
$output = [];
foreach ($this->view->field as $id => $field) {
try {
$value = $this->view->style_plugin
->getField($row_id, $id);
if ($field->option['hide_empty'] && empty($value)) {
continue;
}
if (isset($field->option['type']) && $field->options['type'] == "datetime_default") {
$value = \Drupal::service('date.formatter')
->format(strtotime($value), $field->options['settings']['format_type']);
}
} catch (\TypeError $e) {
$value = false;
} catch (\InvalidArgumentException $e) {
$value = false;
}
if (($alias = $this
->getFieldKeyAlias($id)) && $value) {
if (array_key_exists($alias, $output)) {
$output[$alias] = $this
->convert($output[$alias], $value);
}
else {
$output[$alias] = $value;
}
}
}
return $output;
}
protected function getFieldKeyAlias($id) {
$fields = $this->options['field_mappings'][$this->displayHandler
->getCurrentMetadataPrefix()];
if (isset($fields) && isset($fields[$id]) && $fields[$id] !== 'none') {
return $fields[$id];
}
return NULL;
}
public function getCacheMaxAge() {
return Cache::PERMANENT;
}
public function getCacheContexts() {
return [
'request_format',
];
}
public function getCacheTags() {
return [
'views_oai_pmh',
];
}
protected function getInstancePlugin($plugin_id) : MetadataPrefixInterface {
if (isset($this->pluginInstances[$plugin_id])) {
return $this->pluginInstances[$plugin_id];
}
$this->pluginInstances[$plugin_id] = $this->prefixManager
->createInstance($plugin_id);
return $this->pluginInstances[$plugin_id];
}
}