Skip to content
Snippets Groups Projects
UwNodeFieldValue.php 19.6 KiB
Newer Older
<?php

namespace Drupal\uw_cfg_common\Service;

use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Class UwFieldValue.
 *
 * Gets the data out from individual fields of a node.
 *
 * @package Drupal\uw_cfg_common\Service
 */
  // Date format: "Thursday, December 2, 2021".
  const DATE_FORMAT_DATE_ONLY = 'l, F j, Y';
  // Time format: "10:00 AM".
  const DATE_FORMAT_TIME_ONLY = 'g:i A';
  // Date and time format: "Thursday, December 2, 2021 10:00 AM".
  const DATE_FORMAT_DATE_TIME = 'l, F j, Y g:i A';

   * Entity type manager from core.
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
  protected $entityTypeManager;

  /**
   * The current request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The UW Service.
   *
   * @var UWServiceInterface
   */
  /**
   * Default constructor.
   *
   * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
   *   The current request stack.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
   *   The entity type manager.
   * @param \Drupal\uw_cfg_common\Service\UWServiceInterface $uwService
   *   The UW Service.
   */
  public function __construct(RequestStack $requestStack, EntityTypeManagerInterface $entityTypeManager, UWServiceInterface $uwService) {
    $this->entityTypeManager = $entityTypeManager;
    $this->uwService = $uwService;
  }

  /**
   * Function to get the value of a node field.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string $view_mode
   *   The view mode of the bnode.
   * @param string $type
   *   The type of field.
   * @param mixed $field_name
   *   The name of the field.
   * @param array|null $extra_options
   *   Some extra options if requried.
   *
   * @return array|\Drupal\Core\GeneratedUrl|mixed|string|void|null
   *   Array of the value of the field.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getFieldValue(Node $node, string $view_mode, string $type, $field_name = NULL, array $extra_options = NULL) {
      return $this->getAddressField($node, $field_name);
    }

    // Author field type.
    if ($type == 'author') {
      return $this->getAuthor($node);
    }

    // Long text field type with a text format.
    if ($type == 'formatted_text') {
      return $this->getFormattedText($node, $field_name);
    }

    // Only content, either layout builder or summary.
    if ($type == 'content') {
      return $this->getContentField($node, $view_mode, $field_name);
      $hours = $node->$field_name->view();
      if (isset($hours['#title'])) {
        return $hours;
      }
      else {
        return [];
      }
    }

    // Date field type (smart dates).
    if ($type == 'date') {
      return $this->getDates($node, $field_name, $view_mode);
    }

    // Select list field.
    if ($type == 'select') {
      return $node->$field_name->value;
    }

      return $this->getTermsField($node, $field_name);
      return $this->getImage($node, $field_name, $extra_options);
    }

    // Link field type.
    if ($type == 'link') {
      return $this->getLinkInfo($node, $field_name);
    }

    // Map (leaflet) field type.
    if ($type == 'map') {
      return $this->getMapField($node, $field_name);
    if ($type == 'plain_text' || $type == 'multiple_plain_text') {
      if ($type == 'multiple_plain_text') {
        return $this->getPlainText($node, $field_name, TRUE);
      }
      else {
        return $this->getPlainText($node, $field_name);
      }
    }

    // Source or hero image field type.
    if ($type == 'sources' || $type == 'hero') {
      return $this->getSources($node, $field_name);
    }

    // Catalog tags, this is a special type of terms, since we
    // need to worry about the tabs that go along with them.
    if ($type == 'catalog_terms') {
      return $this->getCatalogTags($node, $field_name);
    }
    // Title of the node.
    if ($type == 'title') {
      return $node->getTitle();
    }
    // URL of the node.
    if ($type == 'url') {
      return $node->toUrl()->toString();
    }
  }
  /**
   * Function to get the formatted text.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string|null $field_name
   *   The name of the field to get.
   *
   * @return array
   *   Render array for formatted text.
   */
  public function getFormattedText(Node $node, string $field_name = NULL): array {

    // Ensure that we have a field to check.
    if ($field_name !== NULL) {

      // Get the value of the field.
      $value = $node->$field_name->value;

      // If the value is not null, then return the
      // formatted text render array.
      if ($value !== NULL) {
        return [
          '#type' => 'processed_text',
          '#text' => $value,
          '#format' => $node->$field_name->format,
        ];
      }
    }

    // If we get here there is no value, so
    // return an empty array and our clean
    // node data function will handle it.
    return [];
  /**
   * Function to get catalog tags.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   *   The field name.
   *
   * @return array
   *   Array of values for the field.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getCatalogTags(Node $node, array $field_name): array {

    // Empty arrays so that we don't get undefined
    // index errors.
    $tabs = [];
    $tags = [];

    // Get the entity and values for the catalog,
    // which is the taxonomy term catalog.
    $catalog_entity = $node->field_uw_catalog_catalog->entity;
    $tabs_values = $catalog_entity->field_uw_catalog_tabs_display->getValue();

    // Setup the array that we can use for in_array,
    // which is the tabs to be displayed.
    foreach ($tabs_values as $tab_value) {
      $tabs[] = $tab_value['value'];
    }
    // If there are tabs, then get them.
    if (!empty($tabs)) {
      foreach ($field_name as $key => $field) {
        if (in_array($key, $tabs)) {
          $tags_to_add = $this->getTermsFromEntityField($node->$field, 'tags');
          if (!empty($tags_to_add)) {
            $tags[$key] = $this->getTermsFromEntityField($node->$field, 'tags');
  /**
   * Gets a plain text field or fields.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string $field_name
   *   The field name.
   * @param bool $multiple
   *   Flag if multiple plain text.
   *
   * @return mixed
   *   Plain text values.
   */
  public function getPlainText(Node $node, string $field_name, bool $multiple = FALSE) {

    // If there are no multiple plain text, just return value.
    // If there are multiple plain text, step through and
    // get the values.
    if (!$multiple) {
      return $node->$field_name->value;
    }
    else {

      // Get the values of the plain text field.
      $values = $node->$field_name->getValue();

      // Step through each and get the actual value.
      foreach ($values as $value) {
        $plain_text[] = $value['value'];
      }

      // Return array of plain text.
      return $plain_text;
    }
  }

   * Prepares image for theme.
   *
   * @param \Drupal\node\Entity\Node $node
   *   Node entity.
   * @param string $field_name
   *   Field name.
   * @param string|null $extra_options
   *   An array of extra options for the image.
   *
   * @return array
   *   Array of data such as url, alt.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
  public function getImage(Node $node, string $field_name, array $extra_options = NULL): array {
    if (isset($extra_options['is_responsive']) && $extra_options['is_responsive']) {
      $image = $this->getSources($node, $field_name);
    }
    else {
      // Get the media id.
      $mid = $node->$field_name->getValue();

      // If there is an image, process it.
      if ($mid) {

        // Load in the media item.
        /** @var \Drupal\media\Entity\Media $media */
        $media = $this->entityTypeManager->getStorage('media')->load($mid[0]['target_id']);

        // Get the file id from the media object.
        $fid = $media->getSource()->getSourceFieldValue($media);

        // If there is a file id, then get the uri,
        // using the thumbnail image style.
        if (isset($extra_options['image_style'])) {
          $file = $this->entityTypeManager->getStorage('file')->load($fid);
          $image['uri'] = $this->entityTypeManager->getStorage('image_style')->load($extra_options['image_style'])->buildUrl($file->getFileUri());
          $image['alt'] = $media->field_media_image->alt;
          $file = $this->entityTypeManager->getStorage('file')->load($fid);
          $image['uri'] = $this->entityTypeManager->getStorage('image_style')->load('thumbnail')->buildUrl($file->getFileUri());
          $image['alt'] = $media->field_media_image->alt;
        }
    // If there is a type for the image, add it to the array.
    if (isset($extra_options['type'])) {
      $image['type'] = $extra_options['type'];
    }

  /**
   * Get the value of a map field.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string $field_name
   *   The field name.
   *
   * @return array|null
   *   Array of field value or NULL.
   */
  public function getMapField(Node $node, string $field_name) {

    // Set the map initially to null, if there are
    // coordinates, then will be replaced.
    $map = NULL;

    // If there are coordinates, set the map.
    if ($node->$field_name->getValue()) {
      $display = [
        'type' => 'leaflet_formatter_default',
        'label' => 'visually_hidden',
      ];
      $map = $node->$field_name->view($display);
    return $map;
  }

  /**
   * Get the value of an content field.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string $view_mode
   *   The view mode.
   * @param string|null $field_name
   * @return array|null
   *   Array of field value or NULL.
   */
  public function getContentField(Node $node, string $view_mode, string $field_name = NULL): ?array {
    // If on the teaser, return the summary field values.
    if ($view_mode == 'teaser') {
      return $this->getFormattedText($node, $field_name);
    return NULL;
  }

  /**
   * Get the taxonomy terms field(s) value.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param array $field_name
   *   Array of field names.
   *
   * @return array
   *   Array of taxonomy term values.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getTermsField(Node $node, array $field_name): array {

    // Need empty array in case there are no terms.
    $tags = [];

    // Step through each of the terms and add to array.
    foreach ($field_name as $field) {
      $tags = array_merge($tags, $this->getTermsFromEntityField($node->$field, 'tags'));
    }

    // Return array of terms.
    return $tags;
  }

  /**
   * Get the value of an address field.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   * @param string $field_name
   *   The field name.
   *
   * @return mixed
   *   Array of field value or NULL.
   */
  public function getAddressField(Node $node, string $field_name) {

    $address = $node->$field_name->getValue();
    if (isset($address[0])) {
      return $address[0];
  }

  /**
   * Get the author of the node.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   *
   * @return array
   *   Array of the author info.
   */
  public function getAuthor(Node $node): array {

    // Get the author field from the node, if there is
    // no author specified the value will be NULL.
    $author_name = $node->field_author->value;

    // If there is no author in the field, get the owner
    // of the blog post.
    if (!$author_name) {

      // Set the author to the person who made blog.
      $author = [
        'name' => $node->getOwner()->getDisplayName(),
      ];
    }

    // If there is an author, get the author name and link.
    else {

      // Get the link field from the node.
      $link = $node->field_uw_author_link->getValue();

      $author['name'] = $author_name;

      if (!empty($link)) {
        $author['link'] = $link[0]['uri'];
      }
   * @param \Drupal\node\Entity\Node $node
   *   Node entity.
   * @param string $field_name
   *   The field name that has the date(s).
   * @param string $view_mode
   *   The view mode of the node.
   *
   * @return array
   *   Array of dates.
   */
  public function getDates(Node $node, string $field_name, string $view_mode): array {

    $return_dates = [];

    // If this is not and event, just get the date.
    if ($node->getType() !== 'uw_ct_event') {
      $return_dates[] = date('l, F j, Y', strtotime($node->$field_name->value));
    }
    else {

      // Get all the dates.
      $dates = $node->$field_name->getValue();

      // Get the date query parameter.
      $date_parameter = $this->requestStack->getCurrentRequest()->query->get('date');

      // If there is a date query parameter, convert
      // to timestamp so we can compare against dates
      // in the event.  If there is no parameter, set
      // the timestamp todays date.
      if ($date_parameter) {
        $check_date = strtotime($date_parameter['value']);
      }
      else {
        $check_date = strtotime("now");
      }

      // Step through each of the dates and get
      // out correct values.
      foreach ($dates as $date) {

        // ISTWCMS-5088: we need to ensure that at least
        // some dates show on the node page, so let's just
        // display them all.
        // If not node page, only get dates in the future.
        if ($view_mode == 'full') {

          $return_dates[] = $this->getDate($date, 'event');
        }
        else {

          // Ensure that the dates are greater than timestamp
          // that we generated above.
          if ($date['end_value'] > $check_date) {
            $return_dates[] = $this->getDate($date, 'event');
          }
        }
      }
    }

    return $return_dates;
  }

  /**
   * Function that parses terms and returns a list.
   *
   * @param \Drupal\Core\Field\EntityReferenceFieldItemListInterface $values
   *   List of values for the provided field.
   * @param string|null $type
   *   The type of terms to get, if none provided just term name returned.
   *
   * @return array
   *   List of terms with name and link.
   *
   * @throws \Drupal\Core\Entity\EntityMalformedException
   */
  public function getTermsFromEntityField(EntityReferenceFieldItemListInterface $values, string $type = NULL): array {

    // Array to hold the terms, need to set to
    // null in case there are no terms to be
    // returned.
    $terms = [];

    // Step through each of the values which is a
    // list of referenced taxonomy terms.
    foreach ($values as $term_ref) {

      // Get the term entity, which is the same as
      // loading the term.
      $term_entity = $term_ref->entity;

      // If there is an entity, set the variable.
      if ($term_entity) {

        // If this is a tags term type, we have to include
        // url and title.  If not just the tag name.
        if ($type === 'tags') {

          // Set the variables.  By default function
          // toUrl on entity uses canonical url.
          $terms[] = [
            'title' => $term_entity->getName(),
            'url' => $term_entity->toUrl()->toString(),
          ];
        }
        else {
          $terms[] = $term_entity->getName();
        }
      }
    }

    // Return an array of term names.
    return $terms;
  }

  /**
   * Gets sources from node.
   *
   * @param \Drupal\node\Entity\Node $node
   *   Node entity.
   * @param string $field_name
   *   The field name that has the date(s).
   *
   * @return array
   *   Either array with responsive image.
   */
  public function getSources(Node $node, string $field_name): array {

    $return_sources = [];

    if ($node->$field_name) {
      // Get the image entity.
      $image = $node->$field_name->entity;

      // If there is an image, get the responsive image sources.
      if ($image) {
        $sources = $this->uwService->prepareResponsiveImage($image, 'uw_ris_media');
      }
      else {
        $sources = NULL;
      }

      if (isset($sources['responsive_sources'])) {
        $return_sources['sources'] = $sources['sources'];
        $return_sources['img_element'] = $sources['img_element']['#uri'];
        $return_sources['alt'] = $sources['alt'];
      }
    }

    return $return_sources;
  }

  /**
   * Get a date in the proper format.
   *
   * @param array $date
   *   An array of date info.
   * @param string $type
   *   The type of date.
   *
   * @return string
   *   A converted date to a string.
   */
  public function getDate(array $date, string $type): string {

    $return_date = '';
    if ($type == 'event') {
      // If this is the same day, get the date and the start and end times.
        $start_date = date(self::DATE_FORMAT_DATE_TIME, $date['value']);
        $end_date = date(self::DATE_FORMAT_TIME_ONLY, $date['end_value']);

        $return_date = $start_date . ' - ' . $end_date . ' ' . date('T', $date['end_value']);
      }
      // This is not the day, get the start and end date with time.
      elseif ($date['duration'] > '1439') {
        $start_date = date(self::DATE_FORMAT_DATE_TIME, $date['value']);
        $end_date = date(self::DATE_FORMAT_DATE_TIME, $date['end_value']);

        $return_date = $start_date . ' - ' . $end_date . ' ' . date('T', $date['end_value']);
      }
      // The all date case, duration is always 1439.
        $return_date = date(self::DATE_FORMAT_DATE_ONLY, $date['value']) . ' (all day)';
      }
    }

    return $return_date;
  }

  /**
   * Gets link info from node.
   *
   * @param \Drupal\node\Entity\Node $node
   *   Node entity.
   * @param string $field_name
   *   The field name that has the date(s).
   *
   * @return array
   *   Array with link info.
   */
  public function getLinkInfo(Node $node, string $field_name): array {

    $return_link_data = [];

    // Get the link from the node.
    $link_data = $node->$field_name->getValue();

    // If there is data in the link, get the variables.
    if ($link_data) {

      // Step through each link and get the info.
      foreach ($link_data as $ld) {

        // Get correct uri, if external just use uri from node
        // value, if not, then generate url from uri.
        if (UrlHelper::isExternal($ld['uri'])) {
          $link_info['uri'] = $ld['uri'];
        }
        else {
          $link_info['uri'] = URL::fromUri($ld['uri'])->toString();
        }
        $link_info['title'] = $ld['title'];

        $return_link_data[] = $link_info;
      }
    }

    return $return_link_data;
  }

}