You are here

class RssFields in Views RSS 8.3

Same name in this branch
  1. 8.3 src/Plugin/views/style/RssFields.php \Drupal\views_rss\Plugin\views\style\RssFields
  2. 8.3 src/Plugin/views/row/RssFields.php \Drupal\views_rss\Plugin\views\row\RssFields
Same name and namespace in other branches
  1. 8.2 src/Plugin/views/row/RssFields.php \Drupal\views_rss\Plugin\views\row\RssFields

Renders an RSS item based on fields.

Plugin annotation


@ViewsRow(
  id = "views_rss_fields",
  title = @Translation("RSS Feed - Fields"),
  help = @Translation("Display fields as RSS items."),
  theme = "views_view_row_rss",
  display_types = {"feed"}
)

Hierarchy

Expanded class hierarchy of RssFields

File

src/Plugin/views/row/RssFields.php, line 26
Definition of Drupal\views\Plugin\views\row\RssFields.

Namespace

Drupal\views_rss\Plugin\views\row
View source
class RssFields extends RowPluginBase {

  /**
   * Does the row plugin support to add fields to it's output.
   *
   * @var bool
   */
  protected $usesFields = TRUE;
  protected function defineOptions() {
    $options = parent::defineOptions();
    $item_elements = views_rss_get('item_elements');
    if (count($item_elements)) {
      foreach ($item_elements as $module => $module_item_elements) {
        foreach (array_keys($module_item_elements) as $element) {
          list($namespace, $element_name) = views_rss_extract_element_names($element, 'core');
          $options['item'][$namespace][$module][$element_name] = array(
            'default' => NULL,
          );
        }
      }
    }
    return $options;
  }
  public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    parent::buildOptionsForm($form, $form_state);
    $initial_labels = array(
      '' => $this
        ->t('- None -'),
    );
    $view_fields_labels = $this->displayHandler
      ->getFieldLabels();
    $view_fields_labels = array_merge($initial_labels, $view_fields_labels);
    $item_elements = views_rss_get('item_elements');
    if (count($item_elements)) {
      foreach ($item_elements as $module => $module_item_elements) {
        foreach ($module_item_elements as $element => $definition) {
          if (!isset($definition['configurable']) || $definition['configurable']) {
            list($namespace, $element_name) = views_rss_extract_element_names($element, 'core');

            // Add fieldset for namespace if not yet added.
            if (!isset($form['item'][$namespace])) {
              $form['item'][$namespace] = array(
                '#type' => 'details',
                '#title' => t('Item elements : @namespace', array(
                  '@namespace' => $namespace,
                )),
                '#description' => t('Select fields containing relevant values for &lt;item&gt; elements in "@namespace" namespace. See <a href="@guide_url">Views RSS documentation</a> for more information.', array(
                  '@namespace' => $namespace,
                  '@guide_url' => Url::fromUri('http://drupal.org/node/1344136'),
                )),
                '#open' => FALSE,
              );
            }

            // Prepare form element.
            $default_value = NULL;
            if (!empty($this->options['item'][$namespace][$module][$element_name])) {
              $default_value = $this->options['item'][$namespace][$module][$element_name];
            }
            elseif (!empty($definition['group'])) {
              $default_value = $this->options['item'][$namespace][$module][$definition['group']][$element_name];
            }
            $form_item = array(
              '#type' => 'select',
              '#title' => Xss::filter(isset($definition['title']) ? $definition['title'] : $element_name),
              '#description' => Xss::filter(isset($definition['description']) ? $definition['description'] : NULL),
              '#options' => $view_fields_labels,
              '#default_value' => $default_value,
            );

            // Allow to overwrite default form element.
            if (!empty($definition['settings form'])) {
              $form_item = array_merge($form_item, $definition['settings form']);

              // Make sure that #options is an associative array.
              if (!empty($definition['settings form']['#options'])) {
                $form_item['#options'] = views_rss_map_assoc($definition['settings form']['#options']);
              }
            }

            // Add help link if provided.
            if (isset($definition['help']) && $definition['help']) {
              $form_item['#description'] .= ' ' . \Drupal::l('[?]', Url::fromUri($definition['help']), array(
                'attributes' => array(
                  'title' => t('Need more information?'),
                ),
              ));
            }

            // Check if element should be displayed in a subgroup.
            if (isset($definition['group']) && $definition['group']) {

              // Add a subgroup to the form if it not yet added.
              if (!isset($form['item'][$namespace][$module][$definition['group']])) {

                // Does module provide the group definition?
                $group_title = !empty($element_groups[$module][$definition['group']]['title']) ? $element_groups[$module][$definition['group']]['title'] : $definition['group'];
                $group_description = !empty($element_groups[$module][$definition['group']]['description']) ? $element_groups[$module][$definition['group']]['description'] : NULL;
                $form['item'][$namespace][$module][$definition['group']] = array(
                  '#type' => 'details',
                  '#title' => Xss::filter($group_title),
                  '#description' => Xss::filter($group_description),
                  '#open' => FALSE,
                );
              }
              $form['item'][$namespace][$module][$definition['group']][$element_name] = $form_item;
            }
            else {
              $form['item'][$namespace][$module][$element_name] = $form_item;
            }
          }
        }
      }
    }
  }
  public function validate() {
    $errors = parent::validate();
    if (!\Drupal::moduleHandler()
      ->moduleExists('views_rss_core')) {
      $errors[] = $this
        ->t('You have to enable <em>Views RSS: Core Elements</em> module to have access to basic feed elements.');
    }
    else {

      // An item MUST contain either a title or description.
      // All other elements are optional according to RSS specification.
      if (empty($this->options['item']['core']['views_rss_core']['title']) && empty($this->options['item']['core']['views_rss_core']['description'])) {
        $errors[] = $this
          ->t('You have to configure either <em>title</em> or <em>description</em> core element.');
      }
    }
    return $errors;
  }
  protected function mapRow($row) {
    $rendered_fields = $raw_fields = array();
    $field_ids = array_keys($this->view->field);
    if (!empty($field_ids)) {
      foreach ($field_ids as $field_id) {

        // Render the final field value.
        $rendered_fields[$field_id] = $this->view->field[$field_id]
          ->theme($row);

        // Also let's keep raw value for further processing.
        $raw_fields[$field_id] = array();
        if (method_exists($this->view->field[$field_id], 'getItems')) {
          $raw_fields[$field_id]['items'] = $this->view->field[$field_id]
            ->getItems($row);
        }
      }
    }

    // Rewrite view rows to XML item rows.
    $item_elements = views_rss_get('item_elements');
    foreach ($rendered_fields as $field_id => $rendered_field) {
      $item = $raw_item = array();
      foreach ($item_elements as $module => $module_item_elements) {
        foreach ($module_item_elements as $element => $definition) {
          list($namespace, $element_name) = views_rss_extract_element_names($element, 'core');
          if (!empty($this->options['item'][$namespace][$module][$element_name])) {
            $field_name = $this->options['item'][$namespace][$module][$element_name];
          }
          elseif (!empty($definition['group']) && !empty($this->options['item'][$namespace][$module][$definition['group']][$element_name])) {
            $field_name = $this->options['item'][$namespace][$module][$definition['group']][$element_name];
          }
          else {
            $field_name = NULL;
          }

          // Assign values for all elements, not only those defined in view settings.
          // If element value is not defined in view settings, let's just assign NULL.
          // It will not be passed to final theme function anyway during processing
          // taking place in template_preprocess_views_view_views_rss().
          if (!empty($rendered_fields[$field_name])) {
            $item[$module][$element] = $rendered_fields[$field_name];
          }
          else {
            $item[$module][$element] = NULL;
          }

          // Keep raw values too.
          if (!empty($raw_fields[$field_name])) {
            $raw_item[$module][$element] = $raw_fields[$field_name];
          }
        }
      }
    }
    $this->view->views_rss['raw_items'][$row->index] = $raw_item;
    return $item;
  }
  public function render($row) {
    static $row_index;
    if (!isset($row_index)) {
      $row_index = 0;
    }
    $item_elements = views_rss_get('item_elements');
    $item_data = $this
      ->mapRow($row);

    // Preprocess whole item array before preprocessing separate elements.
    $hook = 'views_rss_preprocess_item';
    $modules = \Drupal::moduleHandler()
      ->getImplementations($hook);
    $item_variables = array(
      'item' => &$item_data,
      'view' => $this->view,
    );

    // Add raw row if generated based on raw item values provided by field formatter.
    if (!empty($this->view->views_rss['raw_items'][$row->index])) {
      $item_variables['raw'] = $this->view->views_rss['raw_items'][$row->index];
    }
    foreach ($modules as $module) {
      \Drupal::moduleHandler()
        ->invoke($module, $hook, array(
        $item_variables,
      ));
    }
    $item = new \stdClass();
    $item->elements = array();

    // Process each element separately.
    foreach ($item_data as $module => $module_item_elements) {
      foreach ($module_item_elements as $element => $value) {

        // Avoid double encoding: the $value might be already encoded here,
        // depending on the field configuration/processing, and because we know
        // it will be encoded again when the whole feed array will be passed to
        // format_xml_elements(), let's make sure we decode it here first.
        //        if (is_string($value)) {
        //          $value = htmlspecialchars_decode($value, ENT_QUOTES);
        //        }
        // Start building XML element array compatible with format_xml_elements().
        $rss_elements = array(
          array(
            'key' => $element,
            'value' => $value,
          ),
        );

        // Preprocess element initial value if required.
        if (isset($item_elements[$module][$element]['preprocess functions']) && is_array($item_elements[$module][$element]['preprocess functions'])) {
          foreach ($item_elements[$module][$element]['preprocess functions'] as $preprocess_function) {
            if (function_exists($preprocess_function)) {
              $item_variables = array(
                'elements' => &$rss_elements,
                'item' => $item_data,
                'view' => $this->view,
              );

              // Add raw item if provided by field formatter.
              if (!empty($this->view->views_rss['raw_items'][$row->index][$module][$element])) {
                $item_variables['raw'] = $this->view->views_rss['raw_items'][$row->index][$module][$element];
              }
              $preprocess_function($item_variables);
            }
          }
        }

        // If no preprocess function was defined, and we have received
        // #rss_element value (XML element array) from the formatter, it should
        // be added to the feed array without any further modifications.
        //        elseif (
        //          !empty($view->views_rss['raw_items'][$item_key][$module][$element])
        //          && is_array($view->views_rss['raw_items'][$item_key][$module][$element])
        //        ) {
        //          // At this point we don't know yet if we got #rss_elements in raw
        //          // values, so do not overwrite and empty main $rss_elements yet, just
        //          // start working with new $formatter_rss_elements - it could be
        //          // overwritten once we are sure we have all required values.
        //          $formatter_rss_elements = array();
        //          foreach ($view->views_rss['raw_items'][$item_key][$module][$element] as $raw_item) {
        //            if (!empty($raw_item['rendered']['#rss_element'])) {
        //              $formatter_rss_elements[] = $raw_item['rendered']['#rss_element'];
        //            }
        //          }
        //          // Now we can overwrite main $rss_elements.
        //          if (!empty($formatter_rss_elements)) {
        //            $rss_elements = $formatter_rss_elements;
        //          }
        //        }
        // If there is no value and no attributes (in case of self-closing elements)
        // already set for the element at this stage, it is not going to be set
        // at any point further, so the element should not be added to the feed.
        foreach ($rss_elements as $key => $rss_element) {
          if (empty($rss_element['value']) && empty($rss_element['attributes'])) {
            unset($rss_elements[$key]);
          }
        }
        if (empty($rss_elements)) {
          continue;
        }

        // Special processing for title, description and link elements, as these
        // are hardcoded both in template_preprocess_views_view_row_rss() and in
        // views-view-row-rss.html.twig, and we try to keep the compatibility.
        if ($element == 'title' || $element == 'description' || $element == 'link') {
          $rss_element = reset($rss_elements);
          $item->{$element} = $rss_element['value'];
        }
        else {
          $item->elements = array_merge($item->elements, $rss_elements);
        }
      }
    }

    // Merge RDF namespaces in the XML namespaces in case they are used
    // further in the RSS content.
    if (function_exists('rdf_get_namespaces') && !empty($this->view->style_plugin->options['namespaces']['add_rdf_namespaces'])) {
      $xml_rdf_namespaces = array();
      foreach (rdf_get_namespaces() as $prefix => $uri) {
        $xml_rdf_namespaces['xmlns:' . $prefix] = $uri;
      }
      $this->view->style_plugin->namespaces += $xml_rdf_namespaces;
    }

    //    $row_index++;
    $build = array(
      '#theme' => $this
        ->themeFunctions(),
      '#view' => $this->view,
      '#options' => $this->options,
      '#row' => $item,
      '#field_alias' => isset($this->field_alias) ? $this->field_alias : '',
    );
    return drupal_render_root($build);
  }

  /**
   * Retrieves a views field value from the style plugin.
   *
   * @param $index
   *   The index count of the row as expected by views_plugin_style::getField().
   * @param $field_id
   *   The ID assigned to the required field in the display.
   */
  public function getField($index, $field_id) {
    if (empty($this->view->style_plugin) || !is_object($this->view->style_plugin) || empty($field_id)) {
      return '';
    }
    return $this->view->style_plugin
      ->getField($index, $field_id);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property An array of entity type IDs keyed by the property name of their storages.
DependencySerializationTrait::$_serviceIds protected property An array of service IDs keyed by property name used for serialization.
DependencySerializationTrait::__sleep public function 1
DependencySerializationTrait::__wakeup public function 2
MessengerTrait::$messenger protected property The messenger. 29
MessengerTrait::messenger public function Gets the messenger. 29
MessengerTrait::setMessenger public function Sets the messenger.
PluginBase::$configuration protected property Configuration information passed into the plugin. 1
PluginBase::$definition public property Plugins's definition
PluginBase::$displayHandler public property The display object this plugin is for.
PluginBase::$options public property Options for this plugin will be held here.
PluginBase::$pluginDefinition protected property The plugin implementation definition. 1
PluginBase::$pluginId protected property The plugin_id.
PluginBase::$renderer protected property Stores the render API renderer. 3
PluginBase::$view public property The top object of a view. 1
PluginBase::calculateDependencies public function Calculates dependencies for the configured plugin. Overrides DependentPluginInterface::calculateDependencies 14
PluginBase::create public static function Creates an instance of the plugin. Overrides ContainerFactoryPluginInterface::create 62
PluginBase::DERIVATIVE_SEPARATOR constant A string which is used to separate base plugin IDs from the derivative ID.
PluginBase::destroy public function Clears a plugin. Overrides ViewsPluginInterface::destroy 2
PluginBase::doFilterByDefinedOptions protected function Do the work to filter out stored options depending on the defined options.
PluginBase::filterByDefinedOptions public function Filter out stored options depending on the defined options. Overrides ViewsPluginInterface::filterByDefinedOptions
PluginBase::getAvailableGlobalTokens public function Returns an array of available token replacements. Overrides ViewsPluginInterface::getAvailableGlobalTokens
PluginBase::getBaseId public function Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface::getBaseId
PluginBase::getDerivativeId public function Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface::getDerivativeId
PluginBase::getPluginDefinition public function Gets the definition of the plugin implementation. Overrides PluginInspectionInterface::getPluginDefinition 3
PluginBase::getPluginId public function Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface::getPluginId
PluginBase::getProvider public function Returns the plugin provider. Overrides ViewsPluginInterface::getProvider
PluginBase::getRenderer protected function Returns the render API renderer. 1
PluginBase::globalTokenForm public function Adds elements for available core tokens to a form. Overrides ViewsPluginInterface::globalTokenForm
PluginBase::globalTokenReplace public function Returns a string with any core tokens replaced. Overrides ViewsPluginInterface::globalTokenReplace
PluginBase::INCLUDE_ENTITY constant Include entity row languages when listing languages.
PluginBase::INCLUDE_NEGOTIATED constant Include negotiated languages when listing languages.
PluginBase::init public function Initialize the plugin. Overrides ViewsPluginInterface::init 8
PluginBase::isConfigurable public function Determines if the plugin is configurable.
PluginBase::listLanguages protected function Makes an array of languages, optionally including special languages.
PluginBase::pluginTitle public function Return the human readable name of the display. Overrides ViewsPluginInterface::pluginTitle
PluginBase::preRenderAddFieldsetMarkup public static function Moves form elements into fieldsets for presentation purposes. Overrides ViewsPluginInterface::preRenderAddFieldsetMarkup
PluginBase::preRenderFlattenData public static function Flattens the structure of form elements. Overrides ViewsPluginInterface::preRenderFlattenData
PluginBase::queryLanguageSubstitutions public static function Returns substitutions for Views queries for languages.
PluginBase::setOptionDefaults protected function Fills up the options of the plugin with defaults.
PluginBase::summaryTitle public function Returns the summary of the settings in the display. Overrides ViewsPluginInterface::summaryTitle 6
PluginBase::themeFunctions public function Provide a full list of possible theme templates used by this style. Overrides ViewsPluginInterface::themeFunctions 1
PluginBase::trustedCallbacks public static function Lists the trusted callbacks provided by the implementing class. Overrides TrustedCallbackInterface::trustedCallbacks 6
PluginBase::unpackOptions public function Unpack options over our existing defaults, drilling down into arrays so that defaults don't get totally blown away. Overrides ViewsPluginInterface::unpackOptions
PluginBase::usesOptions public function Returns the usesOptions property. Overrides ViewsPluginInterface::usesOptions 8
PluginBase::viewsTokenReplace protected function Replaces Views' tokens in a given string. The resulting string will be sanitized with Xss::filterAdmin. 1
PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT constant Query string to indicate the site default language.
PluginBase::__construct public function Constructs a PluginBase object. Overrides PluginBase::__construct
RowPluginBase::$usesOptions protected property Denotes whether the plugin has an additional options form. Overrides PluginBase::$usesOptions 1
RowPluginBase::preRender public function Allow the style to do stuff before each row is rendered. 4
RowPluginBase::query public function Add anything to the query that we might need to. Overrides PluginBase::query 2
RowPluginBase::submitOptionsForm public function Perform any necessary changes to the form values prior to storage. There is no need for this function to actually store the data. Overrides PluginBase::submitOptionsForm 1
RowPluginBase::usesFields public function Returns the usesFields property. 4
RowPluginBase::validateOptionsForm public function Validate the options form. Overrides PluginBase::validateOptionsForm 1
RssFields::$usesFields protected property Does the row plugin support to add fields to it's output. Overrides RowPluginBase::$usesFields
RssFields::buildOptionsForm public function Provide a form for setting options. Overrides RowPluginBase::buildOptionsForm
RssFields::defineOptions protected function Information about options for all kinds of purposes will be held here. Overrides RowPluginBase::defineOptions
RssFields::getField public function Retrieves a views field value from the style plugin.
RssFields::mapRow protected function
RssFields::render public function Render a row object. This usually passes through to a theme template of some form, but not always. Overrides RowPluginBase::render
RssFields::validate public function Validate that the plugin is correct and can be saved. Overrides PluginBase::validate
StringTranslationTrait::$stringTranslation protected property The string translation service. 1
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
TrustedCallbackInterface::THROW_EXCEPTION constant Untrusted callbacks throw exceptions.
TrustedCallbackInterface::TRIGGER_SILENCED_DEPRECATION constant Untrusted callbacks trigger silenced E_USER_DEPRECATION errors.
TrustedCallbackInterface::TRIGGER_WARNING constant Untrusted callbacks trigger E_USER_WARNING errors.