Score:0

How to change media image private to media image public, just for a specific filemime, and update the url?

eg flag

Using Drupal 9.4. The Media File system is set to Private The Drupal default media type Image is set to private. It now contains hundreds of images. We want to switch only this media type from private to public. We want to keep PDF files private, these are in the Drupal default media type Document.

My process is this. Copy all the images from the private folder over to the public folder, keeping the original sub-directories. Then delete the images from the private folder. Go to > Media Types > Image > Manage fields > Edit image > Field settings - Switch from private to public. Note* It says. There is data for this field in the database. The field settings can no longer be changed. But it accepts the change to public.

Next, update the url in the file managed SQL table, so the url path is public instead of private. This command came from this post. And works great. It updates every file including pdf, word and jpegs. But I just want to update jpeg, png, gif. Can it be modified to only effect a certain filemime? I can run it 1 at a time for each filemime.

UPDATE file_managed SET uri = REPLACE(uri, 'private://', 'public://') where instr(uri, 'private') > 0;

In the SQL File Managed table there is a column filemime. The example data in this is: image/jpeg image/gif application/pdf Would it be something like this to target the filemime

WHERE filemime = 'image/jpeg';
Score:2
in flag

In general, you should avoid updating tables directly in favor of using Drupal's APIs, so I would not recommend using an SQL query like that.

I had to do the exact opposite of this recently - move files from public to private. The process is the same, here's what I did:

  1. Update the file field's settings to point to the new destination, e.g. from private to public. This will ensure any future files go to the new spot. (You noted that you did this.)

  2. Next, we need to update all existing files. To do this, I wrote a post_update hook to move the files for all of the file entities. (This will be in lieu of the SQL query you're trying to use and you also won't need to manipulate the filesystem directly, i.e. no copying files to different directories, etc.) Note that I did use a batch process, but here's the heart of the code:

$new_file_dir = 'public://my-new-file-directory/';

$mimes = [
  'image/jpeg',
  // etc...
];

// Get the file entity ids for the files with your wanted file mimes.
$file_entity_ids = \Drupal::entityTypeManager()
  ->getStorage('file')
  ->getQuery()
  ->condition('filemime', $mimes, 'IN')
  ->execute();

// Load the file entities.
$file_entities = \Drupal::entityTypeManager()
  ->getStorage('file')
  ->loadMultiple($file_entity_ids);

// Move the files associated with the file entities.
foreach ($file_entities as $file) {
  \Drupal::service('file.repository')
    ->move($file, $new_file_dir . $file->getFilename());
}
id flag
This looks good but it does not fully answer the question. The question seeks also to do this only for certain file types.
sonfd avatar
in flag
Sure, I guess I can write that code too.
eg flag
Thank you @sonfd, I see you added the $mimes variable. I will try this soon and post here again
eg flag
I tried it and I get the error `[error] Error: Call to undefined method Drupal\Core\Entity\EntityTypeManager::loadMultiple()`
eg flag
When I hover over loadMultiple, I see Method 'loadMultiple' not found in Drupal\Core\Entity\EntityTypeManagerInterface I think I forgot to add a use a the top of the file
eg flag
I changed it to `\Drupal::entityTypeManager()->getStorage('media')->loadMultiple` Now I get Error: Call to undefined method Drupal\media\Entity\Media::getFilename()
sonfd avatar
in flag
@paulcappucci - sorry, it should be `\Drupal::entityTypeManager()->getStorage('file')->loadMultiple()` since we are working with file entities, not media entities.
eg flag
Yes, thank you. I see is ran using `\Drupal::entityTypeManager()->getStorage('file')->loadMultiple`
eg flag
Starting over with a new test to make sure it is working.
eg flag
I refreshed my test site and started over. This time when I run drush updb I only get No pending updates. and the script does not run. I am not sure what I am doing wrong. It worked on my first test.
eg flag
I named the file - au_modify.post_update.php
eg flag
Its working now. I needed to change the NAME to something else in - post_update_NAME. Because it only runs one time, and it has already run.
eg flag
Thank you @sonfd, This works. The only thing I found was that sub-folders in the private folder were not regenerated in the public folder. Images were placed in the root of the public folder. A /styles folder was generated and all images inside were moved to public. My text page has 3 fields with images and they all go to a destination folder. These folder are the sub-folders. But If I add new images then those sub-folders are regenerated. This works very good and I am not too worried about the loose images in the root of the public folder.
sonfd avatar
in flag
Sounds like you may need more complex logic for defining `$new_file_dir` (perhaps getting the current subdirectory of the file in the private files directory). You could set that to anything you need really, but if you want the files in public, you should make sure the path is prefixed with `public://`.
eg flag
@sonfd. I tested the hook post update on the real site with thousands of images. I found if there is a missing image, the hook stops running and aborts, can it be update so that it resumes on missing image error? This is the error `[error] File 'private://some-name.png' ('/private/some-name.png.png') could not be copied because it does not exist. [error] Update failed: mymodule_post_update_my_name [error] Update aborted by: mymodule_post_update_my_name [error] Finished performing updates.`
sonfd avatar
in flag
Check if the file exists before trying to move it.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.