Something went wrong on our end
UwNodeFieldValue.php 25.44 KiB
<?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
*/
class UwNodeFieldValue {
// 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
*/
protected $uwService;
/**
* 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->requestStack = $requestStack;
$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) {
// Address field type.
if ($type == 'address') {
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);
}
// Office hours field type.
if ($type == 'hours') {
$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;
}
// Taxonomy terms field type.
if ($type == 'terms') {
return $this->getTermsField($node, $field_name);
}
// Image field type.
if ($type == 'image') {
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);
}
// Plain text field type (textbox).
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 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 = [];
// Process banner images.
foreach ($node->$field_name as $banner_item) {
$banner_para = $banner_item->entity;
$type = $banner_para->getType();
$banner = [
'type' => $type,
'big_text' => $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.
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' => $block_content->field_uw_autoplay->value,
// 'slide_speed' => $block_content->field_uw_slide_speed->value,
// 'style' => $block_content->field_uw_text_overlay_style->value,
// 'transition_speed' => $block_content->field_uw_transition_speed->value,
];
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.
* @param array $field_name
* 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');
}
}
}
}
return $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) {
$plain_text = [];
// 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 {
// Empty image array, empty if no image.
$image = [];
// 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);
}
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;
}
else {
$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'];
}
return $image;
}
/**
* 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
* The 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];
}
return NULL;
}
/**
* 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'];
}
}
return $author;
}
/**
* Gets dates from node.
*
* @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) {
$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
// 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).
* @param string|null $extra_options
* An array of extra options.
*
* @return array
* Either array with responsive image.
*/
public function getSources(Node $node, string $field_name, array $extra_options = NULL): 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 {
return [];
}
if (isset($sources['responsive_sources'])) {
$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 {
$return_date = [];
if ($type == 'event') {
// If this is the same day, get the date and the start and end times.
if ($date['duration'] < '1439') {
$return_date['date_range'] = TRUE;
$return_date['same_day'] = TRUE;
$return_date['start_date'] = $date['value'];
$return_date['end_date'] = $date['end_value'];
}
// This is not the day, get the start and end date with time.
elseif ($date['duration'] > '1439') {
$return_date['date_range'] = TRUE;
$return_date['same_day'] = FALSE;
$return_date['start_date'] = $date['value'];
$return_date['end_date'] = $date['end_value'];
}
// The all date case, duration is always 1439.
else {
$return_date['all_day'] = TRUE;
$return_date['date'] = $date['value'];
}
}
else {
$return_date['date'] = $date[0];
}
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;
}
}