Skip to content
Snippets Groups Projects
UwNodeFieldValue.php 34.1 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('teaser');
      if (isset($hours['#title'])) {
        return $hours;
      }
      else {
        return [];
      }
    // The media for the top of the page.
    if ($type == 'media') {
      if ($node->hasField('field_uw_type_of_media')) {
        return [
          'type' => $node->field_uw_type_of_media->value,
          'media' => $this->getMedia($node),
        ];
      }
    // 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);
      }
    // Project members.
    if ($type == 'project_members') {
      return $this->getProjectMembers($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);
    }
    // Timeline from smart date range.
    if ($type == 'timeline') {
      return $this->getTimeline($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 media for the top of the page.
   *
   * @param \Drupal\node\Entity\Node $node
   *   The node.
   *
   * @return array
   *   Render array for formatted text.
   */
  public function getMedia(Node $node): array {

    // Set to empty array in case we do not return anything.
    $media = [];

    // Get the specific type of media.
    switch ($node->field_uw_type_of_media->value) {

      // Get the banner.
      case 'banner':
        $media = $this->getBanner($node, 'field_uw_banner');
        break;

      // Get the image.
      case 'image':
        $media = $this->getSources($node, 'field_uw_hero_image');
        break;

      // Get the remote video media.
      case 'remote_video':
        $media = $this->getRemoteVideo($node, 'field_uw_remote_video');
        break;
    }

    // Return the render things for the media.
    return $media;
  }

  /**
   * Function to get the banner.
   *
   * @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 getBanner(Node $node, string $field_name = NULL): array {

    // Set the banners as empty in case we do not have any.
    $banners = [];

    // Ensure that there is a media with and if so get
    // the classes for the width.
    if ($node->hasField('field_uw_media_width')) {

      // Get the layout builder style based from the node value
      // of media width.
      $layout_builder_style = $layout_style = \Drupal::entityTypeManager()->getStorage('layout_builder_style')->load($node->field_uw_media_width->value);
      // Get the classes associated with the layout builder style.
      $media_width_classes = $layout_builder_style->getClasses();
    }
    // Flag to use page title as big text.
    $use_page_title_big_text_flag = FALSE;

    if ($node->hasField('field_uw_page_title_big_text')) {
      if ($node->field_uw_page_title_big_text->value) {
        $use_page_title_big_text_flag = TRUE;
      }
    }

    // Process banner images.
    foreach ($node->$field_name as $banner_item) {

      $banner_para = $banner_item->entity;
      $type = $banner_para->getType();

      $banner = [
        'type' => $type,
        'big_text' => $use_page_title_big_text_flag ? $node->label() : $banner_para->field_uw_ban_big_text->value,
        'small_text' => $banner_para->field_uw_ban_small_text->value,
      ];

      // Link details needs to be created using for loop.
      foreach ($banner_para->field_uw_ban_link as $link_item) {
        $banner['link'] = $link_item->getUrl()->toString();
      }

      if ($type === 'uw_para_image_banner') {
        $banner['image'] = $this->uwService->prepareResponsiveImage($banner_para->field_uw_ban_image->entity, 'uw_ris_media');
      }
      elseif ($type === 'uw_para_local_video_banner') {
        $banner['image'] = $this->uwService->prepareResponsiveImage($banner_para->field_uw_ban_fallback_image->entity, 'uw_ris_media');
        $banner['video'] = $banner_para->field_uw_ban_video->entity->field_media_file->entity->getFileUri();
      }
      elseif ($type === 'uw_para_vimeo_video_banner') {
        $banner['image'] = $this->uwService->prepareResponsiveImage($banner_para->field_uw_ban_fallback_image->entity, 'uw_ris_media');

        // Vimeo embed needs to be handled same way as links.
        if (isset($banner_para->field_uw_ban_vimeo_video->entity->field_media_oembed_video)) {
          foreach ($banner_para->field_uw_ban_vimeo_video->entity->field_media_oembed_video as $embed_video) {
            $banner['video'] = $embed_video->value;
          }
        }
      }

      // If we are using an image, set the sources and the
      // img_element and remove the image array element.
      // Also add on the alt for the image.
      if (isset($banner['image']['sources'])) {
        $banner['sources'] = $banner['image']['responsive_sources'];
        $banner['img_element'] = $banner['image']['img_element']['#uri'];
        $banner['alt'] = $banner['image']['alt'];
        unset($banner['image']);
      }

      $images[] = $banner;
    }

    $banners = [
      'images' => $images,
      'autoplay' => $node->field_uw_autoplay->value,
      'slide_speed' => $node->field_uw_slide_speed->value,
      'style' => $node->field_uw_text_overlay_style->value,
      'transition_speed' => $node->field_uw_transition_speed->value,
      'media_width' => $media_width_classes ?? NULL,
      'text_overlay' => $node->field_uw_text_overlay_style->value,
      'use_page_title_big_text' => $use_page_title_big_text_flag,
      'bundle' => $node->getType(),
    ];

    return $banners;
  }

  /**
   * Function to get the remote video.
   *
   * @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 getRemoteVideo(Node $node, string $field_name = NULL): array {

    // Get the media object.
    $media = $node->$field_name->entity;

    // Set the remote video URL.
    $remote_video['view']['url'] = $media->field_media_oembed_video->value;

    // Check for YouTube.
    if (preg_match('/^https?:\/\/(?:www\.youtube(?:-nocookie)?\.com\/(watch\?(?:\S+&)?v=|embed\/|.+#.+\/)|youtu\.be\/)([\w\-]{11})(?:[#&?]\S*)?$/', $remote_video['view']['url'])) {

      // Set the type of video to YouTube.
      $remote_video['view']['type'] = 'YouTube';
    }
    // Check for Vimeo.
    elseif (strrpos($remote_video['view']['url'], 'vimeo')) {

      // Set the type of video to Vimeo.
      $remote_video['view']['type'] = 'Vimeo';
    }
    // Generic video.
    else {

      // Set the type of video to Generic.
      $remote_video['view']['type'] = 'Generic';
    }

    // Set the video content to be the rendering of the media object.
    $remote_video['video'] = $this->entityTypeManager->getViewBuilder('media')->view($media, 'default');

    return $remote_video;
  }

  /**
   * 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)) {
          // Set the type of tags, we need special one
          // for catalog category tags.
          switch ($key) {
            case 'Category':
              $type = 'category_tags';
              break;

            case 'Faculty':
              $type = 'faculty_tags';
              break;

            case 'Audience':
              $type = 'audience_tags';
              break;

            default:
              $type = 'tags';
              break;
          }

          // Get the tags to add.
          $tags_to_add = $this->getTermsFromEntityField($node->$field, $type);

          // If tags to add is not empty, then add to the
          // tags array.
          if (!empty($tags_to_add)) {
            $tags[$key] = $this->getTermsFromEntityField($node->$field, $type);
          }

          // If this is a catalog category tag, we need to
          // add in the correct UW url to the term.

            // Get the URL to the catalog taxonomy term.
            $url = Url::fromRoute('entity.taxonomy_term.canonical', ['taxonomy_term' => $catalog_entity->id()])->toString();

            // Ensure we add the correct tag type to the url.
            switch ($type) {
              case 'category_tags':
                $url .= '/category';
                break;

              case 'faculty_tags':
                $url .= '/faculty';
                break;

              case 'audience_tags':
                $url .= '/audience';
                break;
            // Enusre that there is a tag.
            if (isset($tags[$key])) {

              // Step through all the catalog category tags and
              // fix to the correct UW URL.
              foreach ($tags[$key] as $index => $value) {

                // Since the drupal views uses the full title in the
                // url (including all little keywords (the, is, all, of)
                // we need to ensure that we include those in the url
                // for the node.
                $value['url'] = strtolower($value['title']);
                $value['url'] = str_replace(' ', '-', $value['url']);
                $tags[$key][$index]['url'] = $url . '/' . $value['url'];
              }
  /**
   * 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 this is responsive, get the sources.
    if (isset($extra_options['is_responsive'])) {
      // Get the sources for the image.
      $image = $this->getSources($node, $field_name, $extra_options);
      // 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 (!empty($image) && 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 {

    // If there is no author in the field, get the owner
    // of the blog post.
    if (!$node->field_author->value) {

      // 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();

      // Get the auther name from the node.
      $author['name'] = $node->field_author->value;

      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.
   */
  public function getDates(Node $node, string $field_name, string $view_mode) {
    // If there is no dates to process, return empty array.
    if (!$node->$field_name->value) {
      return $return_dates;
    }

    // If this is not and event, just get the date.
    if ($node->getType() !== 'uw_ct_event') {
      $return_dates[] = $this->getDate([$node->$field_name->value], 'blog');
    }
    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
        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');
          }
        }
      }
    }

    // If the dates are an array and there is more than one,
    // sort the array so that the dates appear in order.
    if (
      is_array($return_dates) &&
      count($return_dates) > 1
    ) {

      // Sorting the array by the start date, so that
      // the dates actually appear in the correct order.
      $keys = array_column($return_dates, 'start_date');
      array_multisort($keys, SORT_ASC, $return_dates);
    }

    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' ||
          $type == 'category_tags' ||
          $type == 'faculty_tags' ||
          $type == 'audience_tags'
        ) {

          // Get the url to the term.
          $url = $term_entity->toUrl()->toString();

          // If catalog term we only want the end of the url
          // as we need to redirect to the UW category url.
          if (
            $type == 'category_tags' ||
            $type == 'faculty_tags' ||
            $type == 'audience_tags'
          ) {
            $parts = explode('/', $url);
            $url = end($parts);
          }

          // Set the variables.  By default function
          // toUrl on entity uses canonical url.
          $terms[] = [
            'title' => $term_entity->getName(),
          ];
        }
        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).
   * @param string|null $extra_options
   *   An array of extra options.
  public function getSources(Node $node, string $field_name, array $extra_options = NULL): array {
      // 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 {
        $return_sources['sources'] = $sources['responsive_sources'];
        $return_sources['img_element'] = $sources['img_element']['#uri'];
        $return_sources['alt'] = $sources['alt'];
      }

      // If there is a crop on image, pull out only those sources.
      // If no crop is specified use the default which is responsive.
      if (isset($extra_options['crop'])) {
        $image_styles = $this->uwService->getCropImageStyles($extra_options['crop']);
      }
      else {
        $image_styles = $this->uwService->getCropImageStyles('responsive');
      }

      // Step through and remove any sources that are
      // not going to be in the image.
      foreach ($return_sources['sources'] as $index => $source) {
        if (!in_array($source['style'], $image_styles)) {
          unset($return_sources['sources'][$index]);
        }
      }
    }

    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 array
   *   An array about a date.
  public function getDate(array $date, string $type): array {
    if ($type == 'event') {
      if (date('Ymd', $date['value']) == date('Ymd', $date['end_value'])) {