From 8964b94b9fc92827bf0931e40c477f53c55c628c Mon Sep 17 00:00:00 2001 From: bach Date: Wed, 17 Mar 2021 18:56:01 +0100 Subject: [PATCH] images styles generation custom module --- config/sync/core.extension.yml | 1 + .../images_styles_gen.info.yml | 8 + .../images_styles_gen.module | 95 ++++++ .../images_styles_gen.routing.yml | 7 + .../src/CreateImagesStyles.php | 64 ++++ .../src/Form/ImgStylesGenQueueForm.php | 274 ++++++++++++++++++ 6 files changed, 449 insertions(+) create mode 100644 web/modules/custom/images_styles_gen/images_styles_gen.info.yml create mode 100644 web/modules/custom/images_styles_gen/images_styles_gen.module create mode 100644 web/modules/custom/images_styles_gen/images_styles_gen.routing.yml create mode 100644 web/modules/custom/images_styles_gen/src/CreateImagesStyles.php create mode 100644 web/modules/custom/images_styles_gen/src/Form/ImgStylesGenQueueForm.php diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index 67235ce..2f9785c 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -92,6 +92,7 @@ module: image_delta_formatter: 0 image_effects: 0 imagemagick: 0 + images_styles_gen: 0 inline_entity_form: 0 interval: 0 jquery_ui: 0 diff --git a/web/modules/custom/images_styles_gen/images_styles_gen.info.yml b/web/modules/custom/images_styles_gen/images_styles_gen.info.yml new file mode 100644 index 0000000..7dacba9 --- /dev/null +++ b/web/modules/custom/images_styles_gen/images_styles_gen.info.yml @@ -0,0 +1,8 @@ +name: 'images_styles_cron_gen' +type: module +description: 'helpers for progressive decoupling' +core: 8.x +package: 'custom' +# https://www.flocondetoile.fr/blog/generate-programmatically-image-styles-drupal-8 +# https://www.flocondetoile.fr/blog/using-drupal-8-cron-api-generate-image-styles +# https://www.sitepoint.com/drupal-8-queue-api-powerful-manual-and-cron-queueing/ diff --git a/web/modules/custom/images_styles_gen/images_styles_gen.module b/web/modules/custom/images_styles_gen/images_styles_gen.module new file mode 100644 index 0000000..e26db3f --- /dev/null +++ b/web/modules/custom/images_styles_gen/images_styles_gen.module @@ -0,0 +1,95 @@ +get($entity->getFileUri()); +// /** @var \Drupal\Core\Image\Image $image */ +// if ($image->isValid()) { +// $styles = ImageStyle::loadMultiple(); +// $image_uri = $entity->getFileUri(); +// /** @var \Drupal\image\Entity\ImageStyle $style */ +// foreach ($styles as $style) { +// $destination = $style->buildUri($image_uri); +// $style->createDerivative($image_uri, $destination); +// } +// } +// } +// } + +/** + * Implements hook_entity_insert(). + * Queue generation of all image styles once an Image is uploaded. + */ +// function images_styles_gen_entity_insert(EntityInterface $entity) { +// // TODO: IS THIS EVEN WORKING ???? +// /** @var \Drupal\file\Entity\File $entity */ +// if ($entity instanceof FileInterface) { +// $image = \Drupal::service('image.factory')->get($entity->getFileUri()); +// /** @var \Drupal\Core\Image\Image $image */ +// if ($image->isValid()) { +// $queue = \Drupal::queue('img_styles_gen'); +// $item = new \stdClass(); +// $item->fid = $entity->id(); +// $queue->createItem($item); +// // $data = ['entity' => $entity]; +// // $queue->createItem($data); +// } +// } +// } + +// function images_styles_gen_cron_DISABLED(){ +// $file_storage = \Drupal::entityTypeManager()->getStorage('file'); +// $query = $file_storage->getQuery() +// ->condition('filemime', 'image/%', 'LIKE') +// ->accessCheck(TRUE); +// $results = $query->execute(); +// +// // $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style'); +// // $styles = $styles_storage->loadMultiple(); +// +// /** @var QueueFactory $queue_factory */ +// $queue_factory = \Drupal::service('queue'); +// /** @var QueueInterface $queue */ +// $queue = $queue_factory->get('img_styles_gen'); +// +// foreach ($results as $fid) { +// $item = new \stdClass(); +// $item->fid = $fid; +// $queue->createItem($item); +// +// // $queue->createItem(["fid" => $fid]); +// +// +// // /** @var \Drupal\file\FileInterface|null $file*/ +// // $file_entity = \Drupal::entityTypeManager()->getStorage('file')->load($fid); +// // $image = \Drupal::service('image.factory')->get($file_entity->getFileUri()); +// // +// // if ($image->isValid()) { +// // $image_uri = $file_entity->getFileUri(); +// // /** @var \Drupal\image\Entity\ImageStyle $style */ +// // foreach ($styles as $style) { +// // $destination = $style->buildUri($image_uri); +// // // if destination exists skip +// // if (file_exists($destination)) continue; // skip existing files +// // +// // $data = [ +// // 'style' => $style, +// // 'image_uri' => $image_uri, +// // 'destination' => $destination +// // ]; +// // $queue->createItem($data); +// // \Drupal::logger('images_styles_gen')->notice("created queue from $image_uri to $destination"); +// // } +// +// // } +// } +// } diff --git a/web/modules/custom/images_styles_gen/images_styles_gen.routing.yml b/web/modules/custom/images_styles_gen/images_styles_gen.routing.yml new file mode 100644 index 0000000..05ac81c --- /dev/null +++ b/web/modules/custom/images_styles_gen/images_styles_gen.routing.yml @@ -0,0 +1,7 @@ +images_styles_gen.form: + path: '/admin/config/media/imgstylesgen' + defaults: + _form: '\Drupal\images_styles_gen\Form\ImgStylesGenQueueForm' + _title: 'Images Styles Generator' + requirements: + _permission: 'administer site configuration' diff --git a/web/modules/custom/images_styles_gen/src/CreateImagesStyles.php b/web/modules/custom/images_styles_gen/src/CreateImagesStyles.php new file mode 100644 index 0000000..68fdcc2 --- /dev/null +++ b/web/modules/custom/images_styles_gen/src/CreateImagesStyles.php @@ -0,0 +1,64 @@ +uri; + // $message = 'Creating Styles ...'; + $results = array(); + + // foreach ($items as $item) { + $results[] = $item->style->createDerivative($item->uri, $item->destination); + // } + // $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style'); + // $styles = $styles_storage->loadMultiple(); + // + // foreach ($fids as $fid) { + // /** @var \Drupal\file\FileInterface|null $file*/ + // $file_entity = \Drupal::entityTypeManager()->getStorage('file')->load($fid); + // $file_uri = $file_entity->getFileUri(); + // $image = \Drupal::service('image.factory')->get($file_uri); + // // \Drupal::logger('images_styles_gen')->notice("file_uri is $file_uri"); + // + // if ($image->isValid()) { + // /** @var \Drupal\image\Entity\ImageStyle $style */ + // foreach ($styles as $style) { + // $destination = $style->buildUri($file_uri); + // // if destination exists skip + // if (file_exists($destination)) continue; // skip existing files + // + // $results[] = $style->createDerivative($file_uri, $destination); + // // \Drupal::logger('images_styles_gen')->notice("Generated style $file_uri to $destination"); + // } + // + // } + // + // + // } + // $context['message'] = $message; + // $context['results'] = $results; + $context['message'] = $item->uri . ' processed.'; + $context['results'][] = $item->destination; + } + + public static function createStylesFinishedCallback($success, $results, $operations) { + // The 'success' parameter means no fatal PHP errors were detected. All + // other error management should be handled using 'results'. + if ($success) { + $message = \Drupal::translation()->formatPlural( + count($results), + 'One image processed.', '@count image processed.' + ); + } + else { + $message = t('Finished with an error.'); + } + drupal_set_message($message); + } +} diff --git a/web/modules/custom/images_styles_gen/src/Form/ImgStylesGenQueueForm.php b/web/modules/custom/images_styles_gen/src/Form/ImgStylesGenQueueForm.php new file mode 100644 index 0000000..0542c90 --- /dev/null +++ b/web/modules/custom/images_styles_gen/src/Form/ImgStylesGenQueueForm.php @@ -0,0 +1,274 @@ +queueFactory = $queue; + $this->queueManager = $queue_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('queue'), + $container->get('plugin.manager.queue_worker') + ); + } + + /** + * {@inheritdoc}. + */ + public function getFormId() { + return 'images_styles_gen_form'; + } + + /** + * {@inheritdoc}. + */ + public function buildForm(array $form, FormStateInterface $form_state) { + + $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style'); + + $content_type_id = $form_state->getValue('node_type'); + $style_id = $form_state->getValue('style'); + $batch_size = (int)$form_state->getValue('batch_size'); + + $num_rows = 0; + if ( $content_type_id && $style_id ) { + + $database = \Drupal::database(); + $query = $database->select('file_managed', 'fm'); + $query->join('file_usage', 'fu', 'fm.fid = fu.fid'); + $query->join('node', 'n', 'fu.id = n.nid'); + $query + ->condition('fm.filemime', 'image/%', 'LIKE') + ->condition('fu.type', 'node') + ->condition('n.type', $content_type_id) + ->fields('fm', ['fid', 'uri']) + ->fields('fu', ['id']); + + $results = $query->execute(); + + /** @var \Drupal\image\Entity\ImageStyle $style */ + $style = $styles_storage->load($style_id); + + foreach ($results as $file) { + $destination = $style->buildUri($file->uri); + if (file_exists($destination)) continue; // if destination exists skip + $num_rows++; + } + } + + + // select from content type we'll generate derivatives + $contentTypes = \Drupal::service('entity.manager')-> + getStorage('node_type')->loadMultiple(); + $contentTypesList = [0 => "please choose a content type"]; + foreach ($contentTypes as $contentType) { + $contentTypesList[$contentType->id()] = $contentType->label(); + } + $form['node_type'] = array( + "#type" => "select", + "#title" => "Content type", + '#options' => $contentTypesList, + '#ajax' => [ + 'callback' => '::countAjaxCallback', // don't forget :: when calling a class method. + //'callback' => [$this, 'myAjaxCallback'], //alternative notation + 'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element. + 'event' => 'change', + 'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback. + 'progress' => [ + 'type' => 'throbber', + 'message' => $this->t('counting entries...'), + ], + ] + ); + + // select for which style will generate derivatives + $styles = $styles_storage->loadMultiple(); //, 'card_full', 'linkedmaterial_card' + $stylesList = [0 => "please choose a style"]; + foreach ($styles as $style) { + $stylesList[$style->id()] = $style->label(); + } + $form['style'] = array( + "#type" => "select", + "#title" => "Images Styles", + '#options' => $stylesList, + '#ajax' => [ + 'callback' => '::countAjaxCallback', // don't forget :: when calling a class method. + //'callback' => [$this, 'myAjaxCallback'], //alternative notation + 'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element. + 'event' => 'change', + 'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback. + 'progress' => [ + 'type' => 'throbber', + 'message' => $this->t('counting entries...'), + ], + ] + ); + + $form['batch_size'] = array( + '#type' => 'select', + '#title' => 'Batch size', + '#options' => array( + 10 => '10', + 100 => '100', + 500 => '500', + 1000 => '1000', + 50000 => '5000', + 10000 => '10000', + 0 => 'no limit' + ), + '#ajax' => [ + 'callback' => '::countAjaxCallback', // don't forget :: when calling a class method. + //'callback' => [$this, 'myAjaxCallback'], //alternative notation + 'disable-refocus' => FALSE, // Or TRUE to prevent re-focusing on the triggering element. + 'event' => 'change', + 'wrapper' => 'edit-help-wrapper', // This element is updated with this AJAX callback. + 'progress' => [ + 'type' => 'throbber', + 'message' => $this->t('counting entries...'), + ], + ] + ); + + $form['help-wrapper'] = array( + '#type' => 'container' + ); + + $form['help-wrapper']['help'] = array( + '#type' => 'markup', + // '#prefix' => '
', + '#markup' => $this->t('Please choose a content type and a style.'), + // '#suffix' => '
', + '#attributes' => array( + 'id' => 'help' + ) + ); + + if ($num_rows) { + if($batch_size == 0){ + $batch_size = $num_rows; + } + $form['help-wrapper']['help']['#markup'] = $this->t('Submitting this form will process @batch_size of @number images.', array('@batch_size' => $batch_size, '@number' => $num_rows)); + // $form['actions']['submit']['#disabled'] = FALSE; + // unset($form['actions']['submit']['#attributes']['disabled']); + } + + $form['help-wrapper']['num_rows'] = array( + '#type' => 'hidden', + '#value' => $num_rows, + ); + + // Actions + $form['actions']['#type'] = 'actions'; + + $form['actions']['submit'] = array( + '#type' => 'submit', + '#value' => $this->t('Create image derivatives'), + '#button_type' => 'primary', + // '#disabled' => true, + '#states' => [ + //show this submit only if the num rows is not empty + 'visible' => [ + //don't mistake :input for the type of field. You'll always use + //:input here, no matter whether your source is a select, radio or checkbox element. + ':input[name="num_rows"]' => ['!value' => 0], + ], + ], + ); + + return $form; + } + + // Get the value from example select field and fill + // the textbox with the selected text. + public function countAjaxCallback(array &$form, FormStateInterface $form_state) { + $form['help-wrapper']['#id'] = 'edit-help-wrapper'; + return $form['help-wrapper']; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + $content_type_id = $form_state->getValue('node_type'); + $style_id = $form_state->getValue('style'); + $batch_size = (int)$form_state->getValue('batch_size'); + + $database = \Drupal::database(); + $query = $database->select('file_managed', 'fm'); + $query->join('file_usage', 'fu', 'fm.fid = fu.fid'); + $query->join('node', 'n', 'fu.id = n.nid'); + $query + ->condition('fm.filemime', 'image/%', 'LIKE') + ->condition('fu.type', 'node') + ->condition('n.type', $content_type_id) + ->fields('fm', ['fid', 'uri']) + ->fields('fu', ['id']); + + $results = $query->execute(); + + $styles_storage = \Drupal::entityTypeManager()->getStorage('image_style'); + /** @var \Drupal\image\Entity\ImageStyle $style */ + $style = $styles_storage->load($style_id); + + $operations = []; + foreach ($results as $file) { + $destination = $style->buildUri($file->uri); + + if (file_exists($destination)) continue; // skip existing files + + $batch_item = new \stdClass(); + $batch_item->style = $style; + $batch_item->uri = $file->uri; + $batch_item->destination = $destination; + + $operations[] = ['\Drupal\images_styles_gen\CreateImagesStyles::createStyles', [$batch_item]]; + + if($batch_size && count($operations) >= $batch_size){ + break; + } + } + + $batch = array( + 'title' => t('Creating images derivatives ...'), + 'operations' => $operations, + 'finished' => '\Drupal\images_styles_gen\CreateImagesStyles::createStylesFinishedCallback', + ); + + batch_set($batch); + } +}