Loading src/Plugin/QueueWorker/WidgetQueueWorker.php +61 −0 Original line number Diff line number Diff line Loading @@ -6,14 +6,19 @@ use Composer\Semver\Comparator; use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Queue\QueueWorkerBase; use Drupal\file\Entity\File; use Drupal\file\FileInterface; use Drupal\widget_ingestion\WidgetRemoteRepository; use Drupal\widget_type\Entity\WidgetType; use Drupal\widget_type\WidgetRegistrySourceInterface; use Drupal\widget_type\WidgetTypeConfiguration; use Drupal\widget_type\WidgetTypeInterface; use GuzzleHttp\Exception\GuzzleException; use JsonException; use Symfony\Component\DependencyInjection\ContainerInterface; use const DIRECTORY_SEPARATOR; Loading Loading @@ -209,6 +214,17 @@ final class WidgetQueueWorker extends QueueWorkerBase implements ContainerFactor if ($avail_trans) { $widget_type->setRemoteLanguages($avail_trans); } $preview_url = $data['preview']['url'] ?? NULL; if ($preview_url) { $widget_type->setPreviewLink($preview_url); } $preview_image_url = $data['preview']['thumbnail'] ?? NULL; if ($preview_image_url) { $preview_image = $this->extractPreviewImage($preview_image_url, $widget_type->getRemoteId()); if ($preview_image instanceof FileInterface) { $widget_type->setPreviewImage($preview_image, $widget_type->getName(), $widget_type->getName()); } } $widget_type->save(); } Loading Loading @@ -323,4 +339,49 @@ final class WidgetQueueWorker extends QueueWorkerBase implements ContainerFactor return $assets->getDirectory(); } private function extractPreviewImage(string $source, string $shortcode): ?FileInterface { $parsed = parse_url($source); $basename = basename($parsed['path'] ?? ''); $destination = sprintf('public://widget-types/%s--%s', $shortcode, $basename); $file_system = \Drupal::service('file_system'); $final_destination = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE); // Try opening the file first, to avoid calling prepareDirectory() // unnecessarily. We're suppressing fopen() errors because we want to try // to prepare the directory before we give up and fail. $destination_stream = @fopen($final_destination, 'w+b'); if (!$destination_stream) { // If fopen didn't work, make sure there's a writable directory in place. $dir = $file_system->dirname($final_destination); if (!$file_system->prepareDirectory($dir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) { return NULL; } // Let's try that fopen again. $destination_stream = @fopen($final_destination, 'w+b'); if (!$destination_stream) { return NULL; } } // Stream the request body directly to the final destination stream. $guzzle_options = ['sink' => $destination_stream]; try { // Make the request. Guzzle throws an exception for anything but 200. \Drupal::service('http_client')->get($source, $guzzle_options); } catch (GuzzleException $e) { return NULL; } if (is_resource($destination_stream)) { fclose($destination_stream); } $file = File::create(['uri' => $destination]); try { $file->save(); } catch (EntityStorageException $e) { return NULL; } return $file; } } widget_ingestion.info.yml +1 −1 Original line number Diff line number Diff line Loading @@ -6,4 +6,4 @@ package: Interactive Components configure: entity.widget_registry_source.collection dependencies: - drupal:serialization - widget_type:widget_type - widget_type:widget_type (>=1.5.7) Loading
src/Plugin/QueueWorker/WidgetQueueWorker.php +61 −0 Original line number Diff line number Diff line Loading @@ -6,14 +6,19 @@ use Composer\Semver\Comparator; use Drupal\Component\Utility\NestedArray; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Queue\QueueWorkerBase; use Drupal\file\Entity\File; use Drupal\file\FileInterface; use Drupal\widget_ingestion\WidgetRemoteRepository; use Drupal\widget_type\Entity\WidgetType; use Drupal\widget_type\WidgetRegistrySourceInterface; use Drupal\widget_type\WidgetTypeConfiguration; use Drupal\widget_type\WidgetTypeInterface; use GuzzleHttp\Exception\GuzzleException; use JsonException; use Symfony\Component\DependencyInjection\ContainerInterface; use const DIRECTORY_SEPARATOR; Loading Loading @@ -209,6 +214,17 @@ final class WidgetQueueWorker extends QueueWorkerBase implements ContainerFactor if ($avail_trans) { $widget_type->setRemoteLanguages($avail_trans); } $preview_url = $data['preview']['url'] ?? NULL; if ($preview_url) { $widget_type->setPreviewLink($preview_url); } $preview_image_url = $data['preview']['thumbnail'] ?? NULL; if ($preview_image_url) { $preview_image = $this->extractPreviewImage($preview_image_url, $widget_type->getRemoteId()); if ($preview_image instanceof FileInterface) { $widget_type->setPreviewImage($preview_image, $widget_type->getName(), $widget_type->getName()); } } $widget_type->save(); } Loading Loading @@ -323,4 +339,49 @@ final class WidgetQueueWorker extends QueueWorkerBase implements ContainerFactor return $assets->getDirectory(); } private function extractPreviewImage(string $source, string $shortcode): ?FileInterface { $parsed = parse_url($source); $basename = basename($parsed['path'] ?? ''); $destination = sprintf('public://widget-types/%s--%s', $shortcode, $basename); $file_system = \Drupal::service('file_system'); $final_destination = $file_system->getDestinationFilename($destination, FileSystemInterface::EXISTS_REPLACE); // Try opening the file first, to avoid calling prepareDirectory() // unnecessarily. We're suppressing fopen() errors because we want to try // to prepare the directory before we give up and fail. $destination_stream = @fopen($final_destination, 'w+b'); if (!$destination_stream) { // If fopen didn't work, make sure there's a writable directory in place. $dir = $file_system->dirname($final_destination); if (!$file_system->prepareDirectory($dir, FileSystemInterface:: CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) { return NULL; } // Let's try that fopen again. $destination_stream = @fopen($final_destination, 'w+b'); if (!$destination_stream) { return NULL; } } // Stream the request body directly to the final destination stream. $guzzle_options = ['sink' => $destination_stream]; try { // Make the request. Guzzle throws an exception for anything but 200. \Drupal::service('http_client')->get($source, $guzzle_options); } catch (GuzzleException $e) { return NULL; } if (is_resource($destination_stream)) { fclose($destination_stream); } $file = File::create(['uri' => $destination]); try { $file->save(); } catch (EntityStorageException $e) { return NULL; } return $file; } }
widget_ingestion.info.yml +1 −1 Original line number Diff line number Diff line Loading @@ -6,4 +6,4 @@ package: Interactive Components configure: entity.widget_registry_source.collection dependencies: - drupal:serialization - widget_type:widget_type - widget_type:widget_type (>=1.5.7)