Created on 25 August 2023, 10 months ago
Updated 7 March 2024, 4 months ago

Hi,

I have just a quick question, do you know how I can migrate the crop to Drupal 10? I migrated all the content but the crops are not good.

Thanks

📌 Task
Status

Needs review

Version

1.7

Component

Code

Created by

🇨🇭Switzerland sir_squall

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @sir_squall
  • 🇨🇭Switzerland sir_squall

    Hi,

    Ok for those who are also interrested, i have created a new module with a drush command, and here is the code that will do the migration :

    <?php
    namespace Drupal\drush_migratecrops\Command;
    
    use Drush\Commands\DrushCommands;
    use Drupal\Core\Database\Database;
    use Drupal\Core\Database\DatabaseException;
    use Drupal\Core\Database\Connection;
    use Drupal\crop\Entity\Crop;
    
    
    /**
     * Drush command file.
     */
    class MigrateCropsCommands extends DrushCommands {
    
        /**
         * Drush command that migrates the focal points
         *
         * @command migrate:crops
         * @aliases mcr
         * @usage migrate:crops
         */
        public function migrate_crops() {
            $file_storage =  \Drupal::service('entity_type.manager')->getStorage('file');
            $crop_storage = \Drupal::service('entity_type.manager')->getStorage('crop');
    
    
            // delete previous crops
            $crops = $crop_storage->loadByProperties(['entity_type' => 'file']);
            foreach ($crops as $crop) {
                $crop->delete();
            }
      
            
            $database = Database::getConnection('default', 'migrate');
            $count = $query = $database
                 ->select('file_managed', 'fm')
                   ->fields('fm', ['fid', 'uri','uuid'])
                   ->fields('mc', ['y','x','height', 'width','style_name']);
    
    
            $query->leftJoin('manualcrop', 'mc', 'fm.fid = mc.fid');
    
             $sandbox['last_fid'] = 0;
             $sandbox['num_processed'] = 0;
             $sandbox['num_skipped'] = 0;
             $sandbox['total_items'] = $count->countQuery()->execute()->fetchField();
    
            $results= $query->execute()->fetchAll();
            
            foreach($results as $result) {
                $style_name = $result->style_name;
    
                if(!$style_name) {
                    continue;
                }
    
                // adapt old naming to new style naming
                switch ($style_name) {
                  case 'image_liste' :
                      $style_name = 'image_list';
                      break;
                  case 'partenaire' :
                    $style_name = 'partenaires';
                    break;
                  case 'fond_liste' :
                    $style_name = 'fond_list';
                    break;
                }
    
    
                // get FID on d10
                $files =$file_storage->loadByProperties(['uri' => $result->uri]);
                $file = reset($files) ?: NULL;
    
    
                if (!is_null($file)) {
                 
                    $sandbox['last_fid'] = $file->id();
    
                    $crop_data = [
                              'type' => $style_name,
                              'entity_id' => $file->id(),
                              'entity_type' => $file->getEntityTypeId(),
                              'uri' => $result->uri,
                              'x' => (int) round(($result->x ) + ($result->width / 2)),
                              'y' => (int) round(($result->y )+ ($result->height/ 2)),
                              'width' =>  $result->width,
                              'height' =>  $result->height
                    ];
    
                    try {
                        $crop = $crop_storage
                          ->create($crop_data)
                          ->save();
                    } catch (Exception $e) {
                        $sandbox['num_skipped']++;
                        $this->output()->writeln( 'unable to save: ' . $crop_data);
                        
                    }
    
                    $sandbox['num_processed']++;
    
                } else {
                    $sandbox['num_skipped']++;
                }
                   
            }
    
            
            $this->output()->writeln( 'last_fid: ' . $sandbox['last_fid'] );
            $this->output()->writeln( 'num_processed: ' . $sandbox['num_processed'] );
            $this->output()->writeln( 'num_skipped: ' . $sandbox['num_skipped'] );
            $this->output()->writeln( 'total_items: ' . $sandbox['total_items'] );
            
        }
    }
    
  • 🇪🇸Spain candelas

    @sir_squall thanks for your module. I will try it for my migration.
    Which module did you use for Drupal 10 to replace this one?
    https://www.drupal.org/project/image_widget_crop ?
    Thanks

  • 🇨🇭Switzerland sir_squall

    Hi,

    Yes it's this one the image_widget_crop.

    Thanks

  • 🇪🇸Spain candelas

    Tomorrow I will be testing it.
    I have not made modules in drupal 10.
    For what I see you use a migrate module, aren't you?
    If you can give to me any tip, I would very happy :)
    Thanks

  • 🇪🇸Spain candelas

    @sir_squall THANKS!!!!
    At the end I could work on it today.

    last_fid: 4404
    num_processed: 1168
    num_skipped: 0
    total_items: 1676

    I add here how I made it, just in case someone needs it (there are 13,097 sites using it)

    I have drush 12.4.3.0 and I was getting

    [ReflectionException (-1)]                                                       
      Class "\Drupal\drush_migratecrops\Commands\MigrateCropsCommands" does not exist  

    because I made an drush.services.yml

    They changed how you make it

    drush generate drush:command-file

    and in the DrushMigratecropsCommands.php

    <?php
    
    namespace Drupal\drush_migratecrops\Drush\Commands;
    
    use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
    use Drupal\Core\Utility\Token;
    use Drush\Attributes as CLI;
    use Drush\Commands\DrushCommands;
    use Symfony\Component\DependencyInjection\ContainerInterface;
    use Drupal\Core\Database\Database;
    use Drupal\Core\Database\DatabaseException;
    use Drupal\Core\Database\Connection;
    use Drupal\crop\Entity\Crop;
    
    /**
     * A Drush commandfile.
     *
     * In addition to this file, you need a drush.services.yml
     * in root of your module, and a composer.json file that provides the name
     * of the services file to use.
     */
    final class DrushMigratecropsCommands extends DrushCommands {
    
      /**
       * Constructs a DrushMigratecropsCommands object.
       */
      public function __construct(
        private readonly Token $token,
      ) {
        parent::__construct();
      }
    
      /**
       * {@inheritdoc}
       */
      public static function create(ContainerInterface $container) {
        return new static(
          $container->get('token'),
        );
      }
    
      /**
       * Command description here.
       */
      #[CLI\Command(name: 'drush_migratecrops:command-name', aliases: ['foo'])]
      #[CLI\Argument(name: 'arg1', description: 'Argument description.')]
      #[CLI\Option(name: 'option-name', description: 'Option description')]
      #[CLI\Usage(name: 'drush_migratecrops:command-name foo', description: 'Usage description')]
      public function commandName($arg1, $options = ['option-name' => 'default']) {
        $this->logger()->success(dt('Achievement unlocked.'));
      }
    
      /**
       * An example of the table output format.
       */
      #[CLI\Command(name: 'drush_migratecrops:token', aliases: ['token'])]
      #[CLI\FieldLabels(labels: [
        'group' => 'Group',
        'token' => 'Token',
        'name' => 'Name'
      ])]
      #[CLI\DefaultTableFields(fields: ['group', 'token', 'name'])]
      #[CLI\FilterDefaultField(field: 'name')]
      public function token($options = ['format' => 'table']): RowsOfFields {
        $all = $this->token->getInfo();
        foreach ($all['tokens'] as $group => $tokens) {
          foreach ($tokens as $key => $token) {
            $rows[] = [
              'group' => $group,
              'token' => $key,
              'name' => $token['name'],
            ];
          }
        }
        return new RowsOfFields($rows);
      }
    
       /**
         * Drush command that migrates the focal points
         *
         * @command migrate:crops
         * @aliases mcr
         * @usage migrate:crops
         */
        public function migrate_crops() {
            $file_storage =  \Drupal::service('entity_type.manager')->getStorage('file');
            $crop_storage = \Drupal::service('entity_type.manager')->getStorage('crop');
    
    
            // delete previous crops
            $crops = $crop_storage->loadByProperties(['entity_type' => 'file']);
            foreach ($crops as $crop) {
                $crop->delete();
            }
      
            
            $database = Database::getConnection('default', 'migrate');
            $count = $query = $database
                 ->select('file_managed', 'fm')
                   ->fields('fm', ['fid', 'uri','uuid'])
                   ->fields('mc', ['y','x','height', 'width','style_name']);
    
    
            $query->leftJoin('manualcrop', 'mc', 'fm.fid = mc.fid');
    
             $sandbox['last_fid'] = 0;
             $sandbox['num_processed'] = 0;
             $sandbox['num_skipped'] = 0;
             $sandbox['total_items'] = $count->countQuery()->execute()->fetchField();
    
            $results= $query->execute()->fetchAll();
            
            foreach($results as $result) {
                $style_name = $result->style_name;
    
                if(!$style_name) {
                    continue;
                }
    
                // get FID on d10
                $files =$file_storage->loadByProperties(['uri' => $result->uri]);
                $file = reset($files) ?: NULL;
    
    
                if (!is_null($file)) {
                 
                    $sandbox['last_fid'] = $file->id();
    
                    $crop_data = [
                              'type' => $style_name,
                              'entity_id' => $file->id(),
                              'entity_type' => $file->getEntityTypeId(),
                              'uri' => $result->uri,
                              'x' => (int) round(($result->x ) + ($result->width / 2)),
                              'y' => (int) round(($result->y )+ ($result->height/ 2)),
                              'width' =>  $result->width,
                              'height' =>  $result->height
                    ];
    
                    try {
                        $crop = $crop_storage
                          ->create($crop_data)
                          ->save();
                    } catch (Exception $e) {
                        $sandbox['num_skipped']++;
                        $this->output()->writeln( 'unable to save: ' . $crop_data);
                        
                    }
    
                    $sandbox['num_processed']++;
    
                } else {
                    $sandbox['num_skipped']++;
                }
                   
            }
    
            
            $this->output()->writeln( 'last_fid: ' . $sandbox['last_fid'] );
            $this->output()->writeln( 'num_processed: ' . $sandbox['num_processed'] );
            $this->output()->writeln( 'num_skipped: ' . $sandbox['num_skipped'] );
            $this->output()->writeln( 'total_items: ' . $sandbox['total_items'] );
            
        }
    
    }
    

    Have a very good day!!!!!

  • Status changed to Needs review 5 months ago
  • 🇪🇸Spain candelas

    ah! Drupal 10.2.1.

  • 🇨🇭Switzerland sir_squall

    De nada! Happy that I could help you on that! It took me a bit of time to develop that!

    Have a nice day, next time I go to BCN you can offer me a beer ;)

  • 🇪🇸Spain candelas

    Of course, a beer and a tapa!
    I live now in the country side, but if you come, I will go.
    Now I realize that image_widget_crop doesn't have the manualcrop feature of reusing previous crops in images styles and I will collaborate to make a module to migrate to media_contextual_crop based on your module.
    Just in case you are interested, https://www.drupal.org/project/media_contextual_crop/issues/3415186 💬 drush migrate command to port D7 Manual Crop module to Media Contextual Crop Active
    See you in Barcelona :)

  • 🇨🇭Switzerland sir_squall

    nice thanks a lot !

  • 🇮🇱Israel gdana

    Hi, thank you @sir_squall for this module and also @candelas for the further instructions.
    I've tried running this and have also encountered the message
    Class "\Drupal\drush_migratecrops\Commands\MigrateCropsCommands" does not exist
    @candelas, would you mind explaining what you've done other than generating the file via
    drush generate drush:command-file
    you've written that you've generated drush.services.yml by mistake. What does it mean? Did you create a composer.json file and drush.services.yml? and assuming you did, I'd really appreciate if you'd detail what is written in each file.
    Thank you!
    Dana

  • 🇮🇱Israel gdana

    Sorry, nevermind, I managed to overcome these issues, now dealing with the actual code but will try and figure it out myself before asking dumb questions :)

  • 🇫🇷France DrDam

    Hi,

    just an tiny proposal : the drush command may take a parameter/option as a key-map to manage style_name changes

  • 🇮🇱Israel gdana

    Hi, thanks. Would it be possible to detail the required steps including order?

    What I did was migrate the site/content (thousands of nodes with images), before trying out this module. They were migrated successfully, including field definitions and corresponding images.
    Then I used this migrate module and eventually seemed to run it successfully, although without parameters. I can see the crop table in the database with the correct width, height and fids (and also the calculations regarding X and Y - are these adjustments compatible in all cases...?).
    After all this I found out that all of the image styles the use cropping were not migrated in the initial site migration so I defined one as a first test, enabled image_widget_crop, and defined the field that uses the image style to use image_widget_crop.
    It didn't work... am I missing something? I can see the connection in the table between files and crop parameters but nothing connecting to specific fields or nodes. Should I change the order of actions? missing some step altogether?

    It would be very helpful if you can add some instructions for the module...
    Thank you!

  • 🇨🇭Switzerland sir_squall

    Hi,

    You have to do the standard migration process, once you have your new website with the good image styles, the content migrated and the image migrated, then you can run this little script, if you have renamed the images style, you can also adapt the code, as I did:
    // adapt old naming to new style naming
    switch ($style_name) {
    case 'image_liste' : //OLD ONE
    $style_name = 'image_list'; // NEW ONE
    break;
    case 'partenaire' : //OLD ONE
    $style_name = 'partenaires'; //NEW ONE
    break;
    case 'fond_liste' : //OLD ONE
    $style_name = 'fond_list'; //NEWONE
    break;
    }

    Then you run the command and the crops will be imported successfully, you don't have to take care of the x y, the calculation is the good one.

    Thanks

  • 🇮🇱Israel gdana

    Great, thank you. I will try the whole thing again on a clean slate.

Production build 0.69.0 2024