Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / modules / contrib / media_entity_instagram / src / Plugin / media / Source / Instagram.php
1 <?php
2
3 namespace Drupal\media_entity_instagram\Plugin\media\Source;
4
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\Entity\EntityFieldManagerInterface;
7 use Drupal\Core\Entity\EntityTypeManagerInterface;
8 use Drupal\Core\Field\FieldTypePluginManagerInterface;
9 use Drupal\media\MediaInterface;
10 use Drupal\media\MediaSourceBase;
11 use Drupal\media\MediaSourceFieldConstraintsInterface;
12 use Drupal\media_entity_instagram\InstagramEmbedFetcher;
13 use GuzzleHttp\Client;
14 use Symfony\Component\DependencyInjection\ContainerInterface;
15
16 /**
17  * Provides media type plugin for Instagram.
18  *
19  * @MediaSource(
20  *   id = "instagram",
21  *   label = @Translation("Instagram"),
22  *   description = @Translation("Provides business logic and metadata for Instagram."),
23  *   allowed_field_types = {"string", "string_long", "link"},
24  *   default_thumbnail_filename = "instagram.png"
25  * )
26  */
27 class Instagram extends MediaSourceBase implements MediaSourceFieldConstraintsInterface {
28
29   /**
30    * The instagram fetcher.
31    *
32    * @var \Drupal\media_entity_instagram\InstagramEmbedFetcher
33    */
34   protected $fetcher;
35
36   /**
37    * Guzzle client.
38    *
39    * @var \GuzzleHttp\Client
40    */
41   protected $httpClient;
42
43   /**
44    * Constructs a new class instance.
45    *
46    * @param array $configuration
47    *   A configuration array containing information about the plugin instance.
48    * @param string $plugin_id
49    *   The plugin_id for the plugin instance.
50    * @param mixed $plugin_definition
51    *   The plugin implementation definition.
52    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
53    *   Entity type manager service.
54    * @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
55    *   Entity field manager service.
56    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
57    *   Config factory service.
58    * @param \Drupal\Core\Field\FieldTypePluginManagerInterface $field_type_manager
59    *   The field type plugin manager service.
60    * @param \Drupal\media_entity_instagram\InstagramEmbedFetcher $fetcher
61    *   Instagram fetcher service.
62    * @param \GuzzleHttp\Client $httpClient
63    *   Guzzle client.
64    */
65   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, ConfigFactoryInterface $config_factory, FieldTypePluginManagerInterface $field_type_manager, InstagramEmbedFetcher $fetcher, Client $httpClient) {
66     parent::__construct($configuration, $plugin_id, $plugin_definition, $entity_type_manager, $entity_field_manager, $field_type_manager, $config_factory);
67     $this->fetcher = $fetcher;
68     $this->httpClient = $httpClient;
69   }
70
71   /**
72    * {@inheritdoc}
73    */
74   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
75     return new static(
76       $configuration,
77       $plugin_id,
78       $plugin_definition,
79       $container->get('entity_type.manager'),
80       $container->get('entity_field.manager'),
81       $container->get('config.factory'),
82       $container->get('plugin.manager.field.field_type'),
83       $container->get('media_entity_instagram.instagram_embed_fetcher'),
84       $container->get('http_client')
85     );
86   }
87
88   /**
89    * List of validation regular expressions.
90    *
91    * @var array
92    */
93   public static $validationRegexp = [
94     '@((http|https):){0,1}//(www\.){0,1}instagram\.com/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
95     '@((http|https):){0,1}//(www\.){0,1}instagr\.am/p/(?<shortcode>[a-z0-9_-]+)@i' => 'shortcode',
96   ];
97
98   /**
99    * {@inheritdoc}
100    */
101   public function getMetadataAttributes() {
102     return [
103       'shortcode' => $this->t('Instagram shortcode'),
104       'id' => $this->t('Media ID'),
105       'type' => $this->t('Media type: image or video'),
106       'thumbnail' => $this->t('Link to the thumbnail'),
107       'thumbnail_local' => $this->t("Copies thumbnail locally and return it's URI"),
108       'thumbnail_local_uri' => $this->t('Returns local URI of the thumbnail'),
109       'username' => $this->t('Author of the post'),
110       'caption' => $this->t('Caption'),
111     ];
112   }
113
114   /**
115    * {@inheritdoc}
116    */
117   public function getMetadata(MediaInterface $media, $attribute_name) {
118     if ($attribute_name == 'default_name') {
119       // Try to get some fields that need the API, if not available, just use
120       // the shortcode as default name.
121       $username = $this->getMetadata($media, 'username');
122       $id = $this->getMetadata($media, 'id');
123       if ($username && $id) {
124         return $username . ' - ' . $id;
125       }
126       else {
127         $code = $this->getMetadata($media, 'shortcode');
128         if (!empty($code)) {
129           return $code;
130         }
131       }
132       // Fallback to the parent's default name if everything else failed.
133       return parent::getMetadata($media, 'default_name');
134     }
135     elseif ($attribute_name == 'thumbnail_uri') {
136       return $this->getMetadata($media, 'thumbnail_local');
137     }
138
139     $matches = $this->matchRegexp($media);
140
141     if (!$matches['shortcode']) {
142       return FALSE;
143     }
144
145     if ($attribute_name == 'shortcode') {
146       return $matches['shortcode'];
147     }
148
149     // If we have auth settings return the other fields.
150     if ($instagram = $this->fetcher->fetchInstagramEmbed($matches['shortcode'])) {
151       switch ($attribute_name) {
152         case 'id':
153           if (isset($instagram['media_id'])) {
154             return $instagram['media_id'];
155           }
156           return FALSE;
157
158         case 'type':
159           if (isset($instagram['type'])) {
160             return $instagram['type'];
161           }
162           return FALSE;
163
164         case 'thumbnail':
165           return 'http://instagram.com/p/' . $matches['shortcode'] . '/media/?size=m';
166
167         case 'thumbnail_local':
168           $local_uri = $this->getMetadata($media, 'thumbnail_local_uri');
169
170           if ($local_uri) {
171             if (file_exists($local_uri)) {
172               return $local_uri;
173             }
174             else {
175
176               $directory = dirname($local_uri);
177               file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
178
179               $image_url = $this->getMetadata($media, 'thumbnail');
180
181               $response = $this->httpClient->get($image_url);
182               if ($response->getStatusCode() == 200) {
183                 return file_unmanaged_save_data($response->getBody(), $local_uri, FILE_EXISTS_REPLACE);
184               }
185             }
186           }
187           return FALSE;
188
189         case 'thumbnail_local_uri':
190           if (isset($instagram['thumbnail_url'])) {
191             return $this->configFactory->get('media_entity_instagram.settings')->get('local_images') . '/' . $matches['shortcode'] . '.' . pathinfo(parse_url($instagram['thumbnail_url'], PHP_URL_PATH), PATHINFO_EXTENSION);
192           }
193           return FALSE;
194
195         case 'username':
196           if (isset($instagram['author_name'])) {
197             return $instagram['author_name'];
198           }
199           return FALSE;
200
201         case 'caption':
202           if (isset($instagram['title'])) {
203             return $instagram['title'];
204           }
205           return FALSE;
206
207       }
208     }
209
210     return FALSE;
211   }
212
213   /**
214    * {@inheritdoc}
215    */
216   public function getSourceFieldConstraints() {
217     return ['InstagramEmbedCode' => []];
218   }
219
220   /**
221    * Runs preg_match on embed code/URL.
222    *
223    * @param \Drupal\media\MediaInterface $media
224    *   Media object.
225    *
226    * @return array|bool
227    *   Array of preg matches or FALSE if no match.
228    *
229    * @see preg_match()
230    */
231   protected function matchRegexp(MediaInterface $media) {
232     $matches = [];
233
234     if (isset($this->configuration['source_field'])) {
235       $source_field = $this->configuration['source_field'];
236       if ($media->hasField($source_field)) {
237         $property_name = $media->{$source_field}->first()->mainPropertyName();
238         foreach (static::$validationRegexp as $pattern => $key) {
239           if (preg_match($pattern, $media->{$source_field}->{$property_name}, $matches)) {
240             return $matches;
241           }
242         }
243       }
244     }
245     return FALSE;
246   }
247
248 }