3 namespace Drupal\media_entity_instagram\Plugin\MediaEntity\Type;
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\Entity\EntityFieldManagerInterface;
7 use Drupal\Core\Entity\EntityTypeManagerInterface;
8 use Drupal\Core\Form\FormStateInterface;
9 use Drupal\media_entity\MediaInterface;
10 use Drupal\media_entity\MediaTypeBase;
11 use Drupal\media_entity_instagram\InstagramEmbedFetcher;
12 use GuzzleHttp\Client;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
16 * Provides media type plugin for Instagram.
20 * label = @Translation("Instagram"),
21 * description = @Translation("Provides business logic and metadata for Instagram.")
24 class Instagram extends MediaTypeBase {
27 * Config factory service.
29 * @var \Drupal\Core\Config\ConfigFactoryInterface
31 protected $configFactory;
34 * The instagram fetcher.
36 * @var \Drupal\media_entity_instagram\InstagramEmbedFetcher
43 * @var \GuzzleHttp\Client
45 protected $httpClient;
48 * Constructs a new class instance.
50 * @param array $configuration
51 * A configuration array containing information about the plugin instance.
52 * @param string $plugin_id
53 * The plugin_id for the plugin instance.
54 * @param mixed $plugin_definition
55 * The plugin implementation definition.
56 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
57 * Entity type manager service.
58 * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
59 * Entity field manager service.
60 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
61 * Config factory service.
62 * @param \Drupal\media_entity_instagram\InstagramEmbedFetcher $fetcher
63 * Instagram fetcher service.
64 * @param \GuzzleHttp\Client $httpClient
67 public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, InstagramEmbedFetcher $fetcher, Client $httpClient) {
68 parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $config_factory->get('media_entity.settings'));
69 $this->configFactory = $config_factory;
70 $this->fetcher = $fetcher;
71 $this->httpClient = $httpClient;
77 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
82 $container->get('entity_type.manager'),
83 $container->get('entity_field.manager'),
84 $container->get('config.factory'),
85 $container->get('media_entity_instagram.instagram_embed_fetcher'),
86 $container->get('http_client')
91 * List of validation regular expressions.
95 public static $validationRegexp = [
96 '@((http|https):){0,1}//(www\.){0,1}instagram\.com/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
97 '@((http|https):){0,1}//(www\.){0,1}instagr\.am/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
103 public function providedFields() {
105 'shortcode' => $this->t('Instagram shortcode'),
106 'id' => $this->t('Media ID'),
107 'type' => $this->t('Media type: image or video'),
108 'thumbnail' => $this->t('Link to the thumbnail'),
109 'thumbnail_local' => $this->t("Copies thumbnail locally and return it's URI"),
110 'thumbnail_local_uri' => $this->t('Returns local URI of the thumbnail'),
111 'username' => $this->t('Author of the post'),
112 'caption' => $this->t('Caption'),
119 public function getField(MediaInterface $media, $name) {
120 $matches = $this->matchRegexp($media);
122 if (!$matches['shortcode']) {
126 if ($name == 'shortcode') {
127 return $matches['shortcode'];
130 // If we have auth settings return the other fields.
131 if ($instagram = $this->fetcher->fetchInstagramEmbed($matches['shortcode'])) {
134 if (isset($instagram['media_id'])) {
135 return $instagram['media_id'];
140 if (isset($instagram['type'])) {
141 return $instagram['type'];
146 return 'http://instagram.com/p/' . $matches['shortcode'] . '/media/?size=m';
148 case 'thumbnail_local':
149 $local_uri = $this->getField($media, 'thumbnail_local_uri');
152 if (file_exists($local_uri)) {
157 $directory = dirname($local_uri);
158 file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
160 $image_url = $this->getField($media, 'thumbnail');
162 $response = $this->httpClient->get($image_url);
163 if ($response->getStatusCode() == 200) {
164 return file_unmanaged_save_data($response->getBody(), $local_uri, FILE_EXISTS_REPLACE);
170 case 'thumbnail_local_uri':
171 if (isset($instagram['thumbnail_url'])) {
172 return $this->configFactory->get('media_entity_instagram.settings')->get('local_images') . '/' . $matches['shortcode'] . '.' . pathinfo(parse_url($instagram['thumbnail_url'], PHP_URL_PATH), PATHINFO_EXTENSION);
177 if (isset($instagram['author_name'])) {
178 return $instagram['author_name'];
183 if (isset($instagram['title'])) {
184 return $instagram['title'];
197 public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
199 $bundle = $form_state->getFormObject()->getEntity();
200 $allowed_field_types = ['string', 'string_long', 'link'];
201 foreach ($this->entityFieldManager->getFieldDefinitions('media', $bundle->id()) as $field_name => $field) {
202 if (in_array($field->getType(), $allowed_field_types) && !$field->getFieldStorageDefinition()->isBaseField()) {
203 $options[$field_name] = $field->getLabel();
207 $form['source_field'] = [
209 '#title' => $this->t('Field with source information'),
210 '#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.'),
211 '#default_value' => empty($this->configuration['source_field']) ? NULL : $this->configuration['source_field'],
212 '#options' => $options,
221 public function attachConstraints(MediaInterface $media) {
222 parent::attachConstraints($media);
224 if (isset($this->configuration['source_field'])) {
225 $source_field_name = $this->configuration['source_field'];
226 if ($media->hasField($source_field_name)) {
227 foreach ($media->get($source_field_name) as &$embed_code) {
228 /** @var \Drupal\Core\TypedData\DataDefinitionInterface $typed_data */
229 $typed_data = $embed_code->getDataDefinition();
230 $typed_data->addConstraint('InstagramEmbedCode');
237 * Runs preg_match on embed code/URL.
239 * @param \Drupal\media_entity\MediaInterface $media
243 * Array of preg matches or FALSE if no match.
247 protected function matchRegexp(MediaInterface $media) {
250 if (isset($this->configuration['source_field'])) {
251 $source_field = $this->configuration['source_field'];
252 if ($media->hasField($source_field)) {
253 $property_name = $media->{$source_field}->first()->mainPropertyName();
254 foreach (static::$validationRegexp as $pattern => $key) {
255 if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) {
267 public function getDefaultThumbnail() {
268 return $this->config->get('icon_base') . '/instagram.png';
274 public function thumbnail(MediaInterface $media) {
275 if ($local_image = $this->getField($media, 'thumbnail_local')) {
279 return $this->getDefaultThumbnail();
285 public function getDefaultName(MediaInterface $media) {
286 // Try to get some fields that need the API, if not available, just use the
287 // shortcode as default name.
288 $username = $this->getField($media, 'username');
289 $id = $this->getField($media, 'id');
290 if ($username && $id) {
291 return $username . ' - ' . $id;
294 $code = $this->getField($media, 'shortcode');
300 return parent::getDefaultName($media);