Version 1
[yaffs-website] / web / modules / contrib / media_entity_instagram / src / Plugin / MediaEntity / Type / Instagram.php
diff --git a/web/modules/contrib/media_entity_instagram/src/Plugin/MediaEntity/Type/Instagram.php b/web/modules/contrib/media_entity_instagram/src/Plugin/MediaEntity/Type/Instagram.php
new file mode 100644 (file)
index 0000000..04e3756
--- /dev/null
@@ -0,0 +1,361 @@
+<?php
+
+namespace Drupal\media_entity_instagram\Plugin\MediaEntity\Type;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Entity\EntityFieldManagerInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\media_entity\MediaInterface;
+use Drupal\media_entity\MediaTypeBase;
+use Drupal\media_entity\MediaTypeException;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Instagram\Instagram as InstagramApi;
+
+/**
+ * Provides media type plugin for Instagram.
+ *
+ * @MediaType(
+ *   id = "instagram",
+ *   label = @Translation("Instagram"),
+ *   description = @Translation("Provides business logic and metadata for Instagram.")
+ * )
+ */
+class Instagram extends MediaTypeBase {
+
+  /**
+   * Config factory service.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
+   * Constructs a new class instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   Entity type manager service.
+   * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
+   *   Entity field manager service.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   Config factory service.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $config_factory->get('media_entity.settings'));
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('entity_type.manager'),
+      $container->get('entity_field.manager'),
+      $container->get('config.factory')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [
+      'use_instagram_api' => FALSE,
+    ];
+  }
+
+  /**
+   * List of validation regular expressions.
+   *
+   * @var array
+   */
+  public static $validationRegexp = array(
+    '@((http|https):){0,1}//(www\.){0,1}instagram\.com/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
+    '@((http|https):){0,1}//(www\.){0,1}instagr\.am/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
+  );
+
+  /**
+   * {@inheritdoc}
+   */
+  public function providedFields() {
+    $fields = array(
+      'shortcode' => $this->t('Instagram shortcode'),
+    );
+
+    if ($this->configuration['use_instagram_api']) {
+      $fields += array(
+        'id' => $this->t('Media ID'),
+        'type' => $this->t('Media type: image or video'),
+        'thumbnail' => $this->t('Link to the thumbnail'),
+        'thumbnail_local' => $this->t("Copies thumbnail locally and return it's URI"),
+        'thumbnail_local_uri' => $this->t('Returns local URI of the thumbnail'),
+        'username' => $this->t('Author of the post'),
+        'caption' => $this->t('Caption'),
+        'tags' => $this->t('Tags'),
+      );
+    }
+
+    return $fields;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getField(MediaInterface $media, $name) {
+    $matches = $this->matchRegexp($media);
+
+    if (!$matches['shortcode']) {
+      return FALSE;
+    }
+
+    if ($name == 'shortcode') {
+      return $matches['shortcode'];
+    }
+
+    // If we have auth settings return the other fields.
+    if ($this->configuration['use_instagram_api'] && $instagram = $this->fetchInstagram($matches['shortcode'])) {
+      switch ($name) {
+        case 'id':
+          if (isset($instagram->id)) {
+            return $instagram->id;
+          }
+          return FALSE;
+
+        case 'type':
+          if (isset($instagram->type)) {
+            return $instagram->type;
+          }
+          return FALSE;
+
+        case 'thumbnail':
+          if (isset($instagram->images->thumbnail->url)) {
+            return $instagram->images->thumbnail->url;
+          }
+          return FALSE;
+
+        case 'thumbnail_local':
+          if (isset($instagram->images->thumbnail->url)) {
+            $local_uri = $this->configFactory->get('media_entity_instagram.settings')->get('local_images') . '/' . $matches['shortcode'] . '.' . pathinfo($instagram->images->thumbnail->url, PATHINFO_EXTENSION);
+
+            if (!file_exists($local_uri)) {
+              file_prepare_directory($local_uri, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+
+              $image = file_get_contents($local_uri);
+              file_unmanaged_save_data($image, $local_uri, FILE_EXISTS_REPLACE);
+
+              return $local_uri;
+            }
+          }
+          return FALSE;
+
+        case 'thumbnail_local_uri':
+          if (isset($instagram->images->thumbnail->url)) {
+            return $this->configFactory->get('media_entity_instagram.settings')->get('local_images') . '/' . $matches['shortcode'] . '.' . pathinfo($instagram->images->thumbnail->url, PATHINFO_EXTENSION);
+          }
+          return FALSE;
+
+        case 'username':
+          if (isset($instagram->user->username)) {
+            return $instagram->user->username;
+          }
+          return FALSE;
+
+        case 'caption':
+          if (isset($instagram->caption->text)) {
+            return $instagram->caption->text;
+          }
+          return FALSE;
+
+        case 'tags':
+          if (isset($instagram->tags)) {
+            return implode(" ", $instagram->tags);
+          }
+          return FALSE;
+      }
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
+    $options = [];
+    $bundle = $form_state->getFormObject()->getEntity();
+    $allowed_field_types = ['string', 'string_long', 'link'];
+    foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
+      if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
+        $options[$field_name] = $field->getLabel();
+      }
+    }
+
+    $form['source_field'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Field with source information'),
+      '#description' => $this->t('Field on media entity that stores Instagram embed code or URL. You can create a bundle without selecting a value for this dropdown initially. This dropdown can be populated after adding fields to the bundle.'),
+      '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
+      '#options' => $options,
+    ];
+
+    $form['use_instagram_api'] = [
+      '#type' => 'select',
+      '#title' => $this->t('Whether to use Instagram api to fetch instagrams or not.'),
+      '#description' => $this->t("In order to use Instagram's api you have to create a developer account and an application. For more information consult the readme file."),
+      '#default_value' => empty($this->configuration['use_instagram_api']) ? 0 : $this->configuration['use_instagram_api'],
+      '#options' => [
+        0 => $this->t('No'),
+        1 => $this->t('Yes'),
+      ],
+    ];
+
+    // @todo Evaluate if this should be a site-wide configuration.
+    $form['client_id'] = [
+      '#type' => 'textfield',
+      '#title' => $this->t('Client ID'),
+      '#default_value' => empty($this->configuration['client_id']) ? NULL : $this->configuration['client_id'],
+      '#states' => [
+        'visible' => [
+          ':input[name="type_configuration[instagram][use_instagram_api]"]' => ['value' => '1'],
+        ],
+      ],
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function attachConstraints(MediaInterface $media) {
+    parent::attachConstraints($media);
+
+    if (isset($this->configuration['source_field'])) {
+      $source_field_name = $this->configuration['source_field'];
+      if ($media->hasField($source_field_name)) {
+        foreach ($media->get($source_field_name) as &$embed_code) {
+          /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */
+          $typed_data = $embed_code->getDataDefinition();
+          $typed_data->addConstraint('InstagramEmbedCode');
+        }
+      }
+    }
+  }
+
+  /**
+   * Runs preg_match on embed code/URL.
+   *
+   * @param MediaInterface $media
+   *   Media object.
+   *
+   * @return array|bool
+   *   Array of preg matches or FALSE if no match.
+   *
+   * @see preg_match()
+   */
+  protected function matchRegexp(MediaInterface $media) {
+    $matches = array();
+
+    if (isset($this->configuration['source_field'])) {
+      $source_field = $this->configuration['source_field'];
+      if ($media->hasField($source_field)) {
+        $property_name = $media->{$source_field}->first()->mainPropertyName();
+        foreach (static::$validationRegexp as $pattern => $key) {
+          if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) {
+            return $matches;
+          }
+        }
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Get a single instagram.
+   *
+   * @param string $shortcode
+   *   The instagram shortcode.
+   */
+  protected function fetchInstagram($shortcode) {
+    $instagram = &drupal_static(__FUNCTION__);
+
+    if (!isset($instagram)) {
+      // Check for dependencies.
+      // @todo There is perhaps a better way to do that.
+      if (!class_exists('\Instagram\Instagram')) {
+        drupal_set_message($this->t('Instagram library is not available. Consult the README.md for installation instructions.'), 'error');
+        return;
+      }
+
+      if (!isset($this->configuration['client_id'])) {
+        drupal_set_message($this->t('The client ID is not available. Consult the README.md for installation instructions.'), 'error');
+        return;
+      }
+      if (empty($this->configuration['client_id'])) {
+        drupal_set_message($this->t('The client ID is missing. Please add it in your Instagram settings.'), 'error');
+        return;
+      }
+      $instagram_object = new InstagramApi();
+      $instagram_object->setClientID($this->configuration['client_id']);
+      $result = $instagram_object->getMediaByShortcode($shortcode)->getData();
+
+      if ($result) {
+        return $result;
+      }
+      else {
+        throw new MediaTypeException(NULL, 'The media could not be retrieved.');
+      }
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultThumbnail() {
+    return $this->config->get('icon_base') . '/instagram.png';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function thumbnail(MediaInterface $media) {
+    if ($local_image = $this->getField($media, 'thumbnail_local')) {
+      return $local_image;
+    }
+
+    return $this->getDefaultThumbnail();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultName(MediaInterface $media) {
+    // Try to get some fields that need the API, if not available, just use the
+    // shortcode as default name.
+
+    $username = $this->getField($media, 'username');
+    $id = $this->getField($media, 'id');
+    if ($username && $id) {
+      return $username . ' - ' . $id;
+    }
+    else {
+      $code = $this->getField($media, 'shortcode');
+      if (!empty($code)) {
+        return $code;
+      }
+    }
+
+    return parent::getDefaultName($media);
+  }
+
+}