drupal_yext-8.x-1.0/src/traits/CommonUtilities.php

src/traits/CommonUtilities.php
<?php

namespace Drupal\drupal_yext\traits;

use Drupal\drupal_yext\Yext\FieldMapper;
use Drupal\drupal_yext\Yext\Yext;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Link;
use Drupal\Core\Url;
use Drupal\Core\Logger\RfcLogLevel;
use Drupal\Core\Utility\Error;
use Drupal\node\NodeTypeInterface;
use Drupal\node\Entity\NodeType;

/**
 * General utilities trait.
 *
 * If your class needs to use any of these, add "use CommonUtilities" your class
 * and these methods will be available and mockable in tests.
 */
trait CommonUtilities {

  /**
   * Get an arbitrary element from an nested associative array.
   *
   * @param array $array
   *   An associative array such as [a => [b => c]].
   * @param array $types
   *   The expectable types of c.
   * @param array $keys
   *   The path to the data we want, for example [a, b].
   * @param mixed $default
   *   The default value in case there is no available data. This should
   *   be the same type as $type, and will be ignored if $required is
   *   TRUE.
   * @param bool $required
   *   Whether or not the data is required to be present and non-empty.
   * @param string $required_message
   *   A message to add to the exception in case the data is not
   *   present but required.
   * @param array $options
   *   Can contain cast-as-type (TRUE or FALSE, FALSE being default), if TRUE
   *   we will cast to the first type in $types.
   *
   * @return mixed
   *   Data of type $type.
   */
  public function assocArrayElem(array $array, array $types, array $keys, $default, bool $required = FALSE, string $required_message = '', array $options = []) {
    if (!count($types)) {
      throw new \Exception('The types argument cannot be empty.');
    }
    $default_type = gettype($default);
    if (!in_array($default_type, $types)) {
      throw new \Exception('Default value type is ' . $default_type . ', not in ' . implode(', ', $types));
    }
    $structure = $array;
    foreach ($keys as $key) {
      if (!is_array($structure)) {
        throw new \Exception('We are expecting ' . $key . ' to be an array, it is ' . gettype($structure));
      }
      if (empty($structure[$key])) {
        if ($required) {
          throw new \Exception('Required keys ' . implode(', ', $keys) . ' not present in array. ' . $required_message);
        }
        $structure = $default;
        break;
      }
      $structure = $structure[$key];
    }
    $mytype = gettype($structure);
    if (!in_array($mytype, $types)) {
      if (!empty($options['cast-as-type'])) {
        $structure = settype($structure, $types[0]);
      }
      else {
        throw new \Exception('The return structure is ' . $mytype . ', not in ' . implode(', ', $types));
      }
    }
    return $structure;
  }

  /**
   * Checks to make sure a server is available.
   *
   * @param string $server
   *   A server such as http://drupal.
   * @param string $message
   *   Will be filled with the error message if there is one.
   *
   * @return bool
   *   Whether the server is accessible.
   */
  public function checkServer(string $server, string &$message = '') : bool {
    try {
      $response = serialize($this->httpGet($server));
      $message = 'Call to server resulted in ' . $response;
      return TRUE;
    }
    catch (\Throwable $t) {
      $message = $t->getMessage();
      $this->watchdogThrowable($t);
      return FALSE;
    }
  }

  /**
   * Mockable wrapper around \Drupal::config()->get().
   */
  public function configGet($variable, $default = NULL) {
    $return = \Drupal::config('drupal_yext.general.settings')->get($variable);
    return ($return === NULL) ? $default : $return;
  }

  /**
   * Mockable wrapper around setting a config item.
   */
  public function configSet($variable, $value) {
    $config = \Drupal::service('config.factory')->getEditable('drupal_yext.general.settings');
    $config->set($variable, $value)->save();
  }

  /**
   * Mockable wrapper around \Drupal::entityQuery(...).
   *
   * @param string $type
   *   A type such as node.
   *
   * @return \Drupal\Core\Entity\Query\QueryInterface
   *   The query object that can query the given entity type.
   */
  public function drupalEntityQuery(string $type) {
    return \Drupal::entityQuery($type);
  }

  /**
   * Mockable wrapper around \Drupal::moduleHandler().
   *
   * @return \Drupal\Core\Extension\ModuleHandlerInterface
   *   The module handler.
   */
  public function drupalModuleHandler() {
    return \Drupal::moduleHandler();
  }

  /**
   * Mockable wrapper around date().
   */
  public function date(string $format, $timestamp = NULL) : string {
    if ($timestamp === NULL) {
      return date($format);
    }
    else {
      return date($format, $timestamp);
    }
  }

  /**
   * Mockable wrapper around  \Drupal::messenger()::addMessage().
   */
  protected function drupalSetMessage($message = NULL, $type = 'status', $repeat = FALSE) {
    $messenger = \Drupal::messenger();
    return $messenger->addMessage($message, $type == 'error' ? $messenger::TYPE_ERROR : $messenger::TYPE_STATUS, $repeat);
  }

  /**
   * Wrap \Drupal::service('entity_field.manager')->getFieldDefinitions().
   */
  public function fieldDefinitions(string $entity_type, string $bundle) {
    $entityManager = \Drupal::service('entity_field.manager');
    return $entityManager->getFieldDefinitions($entity_type, $bundle);
  }

  /**
   * Get the field mapping singleton.
   *
   * @return \Drupal\drupal_yext\Yext\FieldMapper
   *   The field mapper singleton.
   */
  public function fieldmap() : FieldMapper {
    return FieldMapper::instance();
  }

  /**
   * Mockable wrapper around \Drupal::httpClient()->get().
   */
  public function httpGet($uri, $options = []) {
    $this->watchdog('Making request to ' . $uri . ' with the following options:');
    $this->watchdog(serialize($options));
    return \Drupal::httpClient()->get($uri, $options);
  }

  /**
   * Get an image from the web and save it in a file.
   *
   * This code is partially based on code in the stage_file_proxy module.
   * See also
   *  http://realityloop.com/blog/2015/10/08/programmatically-attach-files-node-drupal-8
   *
   * @param string $url
   *   An URL which contains an image.
   * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
   *   A Drupal entity.
   * @param string $field_name
   *   An image field on the entity.
   */
  public function imageFromWebToField(string $url, FieldableEntityInterface $entity, string $field_name) {
    $response = $this->httpGet($url);
    $response_code = $response->getStatusCode();
    if ($response_code != 200) {
      throw new \Exception($url . ' results in response code ' . $response_code);
    }
    $response_headers = $response->getHeaders();
    $header_length = array_shift($response_headers['Content-Length']);
    $header_type = array_shift($response_headers['Content-Type']);
    $content = $response->getBody()->getContents();
    $content_length = strlen($content);
    if (!in_array($header_type, ['image/jpeg', 'image/png'])) {
      throw new \Exception($header_type . ' is unrecognized.');
    }
    if ($header_length != $content_length) {
      throw new \Exception('Possible incomplete download: ' . $content_length . ' bytes downloaded, ' . $header_length . ' expected.');
    }

    $file = $this->drupalService('file.repository')->writeData($content, 'public://' . $entity->uuid() . '.' . str_replace('image/', '', $header_type), FileSystemInterface::EXISTS_REPLACE);

    $entity->set($field_name, $file);
  }

  /**
   * Mockable wrapper around \Drupal::service(...).
   *
   * @param string $name
   *   A service name like file.repository.
   *
   * @return mixed
   *   The Drupal service, if possible.
   */
  public function drupalService(string $name) {
    return \Drupal::service($name);
  }

  /**
   * Get a link with text and a path.
   *
   * This is relatively equivalent to the l() function in Drupal 7.
   *
   * @return \Drupal\Core\Link
   *   A displayable link.
   */
  public function link(string $text, string $path) : Link {
    return Link::fromTextAndUrl($text, Url::fromUri($path));
  }

  /**
   * Wrapper around NodeType::load() which throws exception if no such type.
   */
  public function nodeTypeLoad(string $type) : NodeTypeInterface {
    $return = NodeType::load($type);
    if (!$return) {
      throw new \Exception('Could not load node type ' . $type);
    }
    return $return;
  }

  /**
   * Mockable wrapper around \Drupal::state()->get().
   */
  public function stateGet($variable, $default = NULL) {
    return \Drupal::state()->get($variable, $default);
  }

  /**
   * Mockable wrapper around \Drupal::state()->set().
   */
  public function stateSet($variable, $value) {
    \Drupal::state()->set($variable, $value);
  }

  /**
   * Log a string to the watchdog.
   *
   * @param string $string
   *   String to be logged.
   */
  public function watchdog(string $string) {
    \Drupal::logger('drupal_yext')->notice($string);
  }

  /**
   * Log an error to the watchdog.
   *
   * @param string $string
   *   String to be logged.
   */
  public function watchdogError(string $string) {
    \Drupal::logger('drupal_yext')->error($string);
  }

  /**
   * Log a \Throwable to the watchdog.
   *
   * Based on
   * https://api.drupal.org/api/drupal/core%21includes%21bootstrap.inc/function/watchdog_exception/8.2.x
   * to work with \Throwables as well as \Exceptions.
   *
   * @param \Throwable $t
   *   A \throwable.
   * @param mixed $message
   *   The message to store in the log. If empty, a text that contains all
   *   useful information about the passed-in exception is used.
   * @param mixed $variables
   *   Array of variables to replace in the message on display or NULL if
   *   message is already translated or not possible to translate.
   * @param mixed $severity
   *   The severity of the message, as per RFC 3164.
   * @param mixed $link
   *   $link: A link to associate with the message.
   */
  public function watchdogThrowable(\Throwable $t, $message = NULL, $variables = [], $severity = RfcLogLevel::ERROR, $link = NULL) {

    // Use a default value if $message is not set.
    if (empty($message)) {
      $message = '%type: @message in %function (line %line of %file).';
    }

    if ($link) {
      $variables['link'] = $link;
    }

    $variables += Error::decodeException($t);

    \Drupal::logger('drupal_yext')->log($severity, $message, $variables);
  }

  /**
   * Get the Yext app singleton.
   *
   * @return \Drupal\drupal_yext\Yext\Yext
   *   The Yext singleton.
   */
  public function yext() {
    return Yext::instance();
  }

  /**
   * The Drupal node type which will be populated by Yext data.
   *
   * @return string
   *   A node type such as 'article'.
   */
  public function yextNodeType() : string {
    return $this->configGet('target_node_type', 'article');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc