class Record in Views OAI-PMH 8
Plugin annotation
@ViewsStyle(
id = "views_oai_pmh_record",
title = @Translation("OAI-PMH"),
help = @Translation("Displays rows in OAI-PMH records."),
display_types = {"oai_pmh"}
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
- class \Drupal\views\Plugin\views\PluginBase implements DependentPluginInterface, ContainerFactoryPluginInterface, TrustedCallbackInterface, ViewsPluginInterface
- class \Drupal\views\Plugin\views\style\StylePluginBase
- class \Drupal\views_oai_pmh\Plugin\views\style\Record implements CacheableDependencyInterface uses ValueConvertTrait
- class \Drupal\views\Plugin\views\style\StylePluginBase
- class \Drupal\views\Plugin\views\PluginBase implements DependentPluginInterface, ContainerFactoryPluginInterface, TrustedCallbackInterface, ViewsPluginInterface
- class \Drupal\Core\Plugin\PluginBase uses DependencySerializationTrait, MessengerTrait, StringTranslationTrait
Expanded class hierarchy of Record
File
- src/
Plugin/ views/ style/ Record.php, line 32
Namespace
Drupal\views_oai_pmh\Plugin\views\styleView source
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;
/**
* @var \Drupal\views_oai_pmh\Plugin\views\display\OAIPMH
*/
public $displayHandler;
protected $repository;
protected $provider;
protected $pluginInstances = [];
/**
* {@inheritdoc}
*/
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'));
}
/**
* Record constructor.
*
* @param array $configuration
* @param $plugin_id
* @param $plugin_definition
* @param \Drupal\views_oai_pmh\Service\FormatRowToXml $rowToXml
* @param \Drupal\views_oai_pmh\Plugin\MetadataPrefixManager $prefixManager
* @param \Symfony\Component\Serializer\Serializer $serializer
* @param \Drupal\views_oai_pmh\Service\Repository $repository
* @param \Drupal\views_oai_pmh\Service\Provider $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;
}
}
/**
* @param $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
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'],
]),
// '#theme' => 'views_oai_pmh_field_mappings_form',
'#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],
];
}
}
}
/**
* {@inheritdoc}
*/
public function render() {
$rows = $this
->getResultRows();
/** @var \Drupal\views_oai_pmh\Plugin\MetadataPrefixInterface $currentPrefixPlugin */
$currentPrefixPlugin = $this->prefixManager
->createInstance($this->displayHandler
->getCurrentMetadataPrefix());
$records = [];
foreach ($rows as $row_id => $row) {
$this->rowToXml
->resetTagsPrefixedWith0();
// Getting all the elements.
$elements = $this->rowToXml
->transform($row);
$element_or_null = array_shift($elements);
// Insure we're adding (union) arrays, not null.
$element = $element_or_null ? $element_or_null : array();
// Getting only the root elements, we need to remove the root elements
// from the list with all the elements to prepare the correct structure.
$root_elements = $element + $currentPrefixPlugin
->getRootNodeAttributes();
// Getting the elements in the level the need to be.
$data = $root_elements + $elements;
// path id for datacite, dcc or dc
$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(),
]));
// Removing empty elements.
$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;
}
/**
* The identifier for record header
*
* @param $id
*
* @return string
* format: oai:domain/nid
*/
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;
}
/**
* Get result that view expose as cartesian product removing duplicates tuples
*
* @return array
*/
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;
}
}
//$rows = $this->removeDuplicates($rows);
return $rows;
}
/**
* Remove all duplicate rows for array considering array keys and key brothers
* @todo refactor this function to more elegant and faster
*
* @param $array
* @return array
*/
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) {
//datacite
$delimiter = '>';
$key_delimiter = '@';
}
else {
if (strpos($key_i, 'dc') !== false) {
//dcc
$delimiter = '@';
}
}
$brothers = $this
->getBrothersKey($key_i, $value, $delimiter, $key_delimiter);
if ($all_equal && empty($brothers)) {
// all values equals and without brother(s)
$output[$key][$key_i] = $value_old;
}
else {
if (!$all_equal && empty($brothers)) {
// not all values are equals and without brother(s) for dc, dcc cases
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 {
// has brother key
$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;
}
/**
* Get all brothers for a key in an array
*
* @param $key
* @param $array
* @param $delimiter
* e.g. >
* @param $key_delimiter
* e.g. @
*
* @return array
*/
public function getBrothersKey($key, $array, $delimiter, $key_delimiter) {
$parts = explode($delimiter, $key);
$sub_key = "";
$output = [];
if ($delimiter === ">") {
// datacite
if (count($parts) <= 1) {
return $output;
}
if (count($parts) < 3 || strpos($key, $key_delimiter) !== false) {
return $output;
}
// Compose family key (sub_key)
for ($i = 0; $i < count($parts) - 1; $i++) {
if ($sub_key === "") {
$sub_key = $parts[$i];
}
else {
$sub_key = $sub_key . $delimiter . $parts[$i];
}
}
}
else {
// dcc
// Only one sub_key
$sub_key = $parts[0];
}
foreach ($array as $key => $value) {
if (strpos($key, $sub_key) !== false) {
$output[] = [
$key => $value,
];
}
}
// Remove if has only one value
if (count($output) === 1) {
$output = [];
}
return $output;
}
/**
* Return a formatted row value in array with all values as cartesian product of rows
*
* @param ResultRow $row
*
* @return array
*
*/
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) {
// If relations are NULL's.
$value = false;
} catch (\InvalidArgumentException $e) {
// If an invalid value was passed to format()
$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;
}
/**
* Get alias for a key in fields list
*
* @param $id
*
* @return array|null
*/
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;
}
/**
* {@inheritdoc}
*/
public function getCacheMaxAge() {
return Cache::PERMANENT;
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return [
'request_format',
];
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
return [
'views_oai_pmh',
];
}
/**
* Get plugin entity for some plugin id
*
* @param $plugin_id
*
* @return \Drupal\views_oai_pmh\Plugin\MetadataPrefixInterface
* @throws \Drupal\Component\Plugin\Exception\PluginException
*/
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];
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DependencySerializationTrait:: |
protected | property | An array of entity type IDs keyed by the property name of their storages. | |
DependencySerializationTrait:: |
protected | property | An array of service IDs keyed by property name used for serialization. | |
DependencySerializationTrait:: |
public | function | 1 | |
DependencySerializationTrait:: |
public | function | 2 | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
public | property | Plugins's definition | |
PluginBase:: |
public | property | Options for this plugin will be held here. | |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
protected | property | Stores the render API renderer. | 3 |
PluginBase:: |
public | property | The top object of a view. | 1 |
PluginBase:: |
public | function |
Calculates dependencies for the configured plugin. Overrides DependentPluginInterface:: |
14 |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
protected | function | Do the work to filter out stored options depending on the defined options. | |
PluginBase:: |
public | function |
Filter out stored options depending on the defined options. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public | function |
Returns an array of available token replacements. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
3 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function |
Returns the plugin provider. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
protected | function | Returns the render API renderer. | 1 |
PluginBase:: |
public | function |
Adds elements for available core tokens to a form. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public | function |
Returns a string with any core tokens replaced. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
constant | Include entity row languages when listing languages. | ||
PluginBase:: |
constant | Include negotiated languages when listing languages. | ||
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginBase:: |
protected | function | Makes an array of languages, optionally including special languages. | |
PluginBase:: |
public | function |
Return the human readable name of the display. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public static | function |
Moves form elements into fieldsets for presentation purposes. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public static | function |
Flattens the structure of form elements. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public static | function | Returns substitutions for Views queries for languages. | |
PluginBase:: |
protected | function | Fills up the options of the plugin with defaults. | |
PluginBase:: |
public | function |
Handle any special handling on the validate form. Overrides ViewsPluginInterface:: |
16 |
PluginBase:: |
public | function |
Returns the summary of the settings in the display. Overrides ViewsPluginInterface:: |
6 |
PluginBase:: |
public | function |
Provide a full list of possible theme templates used by this style. Overrides ViewsPluginInterface:: |
1 |
PluginBase:: |
public | function |
Unpack options over our existing defaults, drilling down into arrays
so that defaults don't get totally blown away. Overrides ViewsPluginInterface:: |
|
PluginBase:: |
public | function |
Returns the usesOptions property. Overrides ViewsPluginInterface:: |
8 |
PluginBase:: |
protected | function | Replaces Views' tokens in a given string. The resulting string will be sanitized with Xss::filterAdmin. | 1 |
PluginBase:: |
constant | Query string to indicate the site default language. | ||
Record:: |
public | property |
Overrides PluginBase:: |
|
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property | ||
Record:: |
protected | property |
Does the style plugin for itself support to add fields to its output. Overrides StylePluginBase:: |
|
Record:: |
protected | property |
Denotes whether the plugin has an additional options form. Overrides StylePluginBase:: |
|
Record:: |
protected | property |
Does the style plugin support custom css class for the rows. Overrides StylePluginBase:: |
|
Record:: |
protected | property |
Whether or not this style uses a row plugin. Overrides StylePluginBase:: |
|
Record:: |
public | function |
Overrides StylePluginBase:: |
|
Record:: |
public static | function |
Creates an instance of the plugin. Overrides PluginBase:: |
|
Record:: |
public | function | Get all brothers for a key in an array | |
Record:: |
public | function |
The cache contexts associated with this object. Overrides CacheableDependencyInterface:: |
|
Record:: |
public | function |
The maximum age for which this object may be cached. Overrides CacheableDependencyInterface:: |
|
Record:: |
public | function |
The cache tags associated with this object. Overrides CacheableDependencyInterface:: |
|
Record:: |
protected | function | Get alias for a key in fields list | |
Record:: |
protected | function | The identifier for record header | |
Record:: |
protected | function | Get plugin entity for some plugin id | |
Record:: |
protected | function | Get result that view expose as cartesian product removing duplicates tuples | |
Record:: |
protected | function | Return a formatted row value in array with all values as cartesian product of rows | |
Record:: |
protected | function | Remove all duplicate rows for array considering array keys and key brothers @todo refactor this function to more elegant and faster | |
Record:: |
public | function |
Render the display in this style. Overrides StylePluginBase:: |
|
Record:: |
public | function |
Record constructor. Overrides ValueConvertTrait:: |
|
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
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. | |
StylePluginBase:: |
protected | property | Should field labels be enabled by default. | 1 |
StylePluginBase:: |
protected | property | The theme function used to render the grouping set. | |
StylePluginBase:: |
protected | property | Stores the rendered field values, keyed by the row index and field name. | |
StylePluginBase:: |
protected | property | Store all available tokens row rows. | |
StylePluginBase:: |
protected | property | Does the style plugin support grouping of rows. | 3 |
StylePluginBase:: |
public | function | Called by the view builder to see if this style handler wants to interfere with the sorts. If so it should build; if it returns any non-TRUE value, normal sorting will NOT be added to the query. | 1 |
StylePluginBase:: |
public | function | Called by the view builder to let the style build a second set of sorts that will come after any other sorts in the view. | 1 |
StylePluginBase:: |
public | function | Return TRUE if this style enables field labels by default. | 1 |
StylePluginBase:: |
protected | function |
Information about options for all kinds of purposes will be held here. Overrides PluginBase:: |
9 |
StylePluginBase:: |
public | function |
Clears a plugin. Overrides PluginBase:: |
|
StylePluginBase:: |
public | function | #pre_render callback for view row field rendering. | |
StylePluginBase:: |
public | function | Should the output of the style plugin be rendered even if it's a empty view. | 2 |
StylePluginBase:: |
public | function | Gets a rendered field. | |
StylePluginBase:: |
public | function | Get the raw field value. | |
StylePluginBase:: |
public | function | Return the token replaced row class for the specified row. | |
StylePluginBase:: |
public | function |
Overrides \Drupal\views\Plugin\views\PluginBase::init(). Overrides PluginBase:: |
|
StylePluginBase:: |
public | function | Allow the style to do stuff before each row is rendered. | |
StylePluginBase:: |
public | function |
Add anything to the query that we might need to. Overrides PluginBase:: |
1 |
StylePluginBase:: |
protected | function | Renders all of the fields for a given style and store them on the object. | |
StylePluginBase:: |
public | function | Group records as needed for rendering. | |
StylePluginBase:: |
public | function | Render the grouping sets. | |
StylePluginBase:: |
protected | function | Renders a group of rows of the grouped view. | |
StylePluginBase:: |
public | function | Take a value and apply token replacement logic to it. | |
StylePluginBase:: |
public static | function |
Lists the trusted callbacks provided by the implementing class. Overrides PluginBase:: |
|
StylePluginBase:: |
public | function | Return TRUE if this style also uses fields. | 3 |
StylePluginBase:: |
public | function | Returns the usesGrouping property. | 3 |
StylePluginBase:: |
public | function | Returns the usesRowClass property. | 3 |
StylePluginBase:: |
public | function | Returns the usesRowPlugin property. | 10 |
StylePluginBase:: |
public | function | Return TRUE if this style uses tokens. | |
StylePluginBase:: |
public | function |
Validate that the plugin is correct and can be saved. Overrides PluginBase:: |
|
StylePluginBase:: |
public | function |
Validate the options form. Overrides PluginBase:: |
|
StylePluginBase:: |
public | function | Provide a form in the views wizard if this style is selected. | |
StylePluginBase:: |
public | function | Alter the options of a display before they are added to the view. | 1 |
TrustedCallbackInterface:: |
constant | Untrusted callbacks throw exceptions. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger silenced E_USER_DEPRECATION errors. | ||
TrustedCallbackInterface:: |
constant | Untrusted callbacks trigger E_USER_WARNING errors. | ||
ValueConvertTrait:: |
public | function |