summaryrefslogtreecommitdiff
path: root/sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc
diff options
context:
space:
mode:
Diffstat (limited to 'sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc')
-rw-r--r--sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc306
1 files changed, 306 insertions, 0 deletions
diff --git a/sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc b/sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc
new file mode 100644
index 000000000..e8620d439
--- /dev/null
+++ b/sites/all/modules/media_browser_plus/includes/media_browser_plus.folders.inc
@@ -0,0 +1,306 @@
+<?php
+/**
+ * @file
+ * Folder manipulation functions.
+ */
+
+/**
+ * Moves the root folder of media files.
+ *
+ * Updates the variable media_root_folder too.
+ *
+ * @param string $source
+ * Source path.
+ * @param string $destination
+ * Destination path.
+ */
+function media_browser_plus_move_root_folder($source, $destination) {
+ if (!empty($source)) {
+ $source .= '/';
+ }
+ if (!empty($destination)) {
+ $destination .= '/';
+ }
+ // Load root folder term.
+ $root_folder_term = media_browser_plus_get_media_root_folder();
+
+ // Prepare destination.
+ foreach (media_get_local_stream_wrappers() as $scheme => $scheme_info) {
+ $directory = file_stream_wrapper_uri_normalize($scheme . '://' . $destination);
+ file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ }
+ variable_set('media_root_folder', trim($destination, '/'));
+
+ // Move media files in root folder itself. We do this because if the root
+ // folder was located in the default file directory of Drupal we can't move
+ // all files / folders.
+ $file_query = new EntityFieldQuery();
+ $files = $file_query
+ ->entityCondition('entity_type', 'file')
+ ->fieldCondition('field_folder', 'tid', $root_folder_term->tid)
+ ->execute();
+ if (!empty($files['file'])) {
+ $file_entities = file_load_multiple(array_keys($files['file']));
+ foreach ($file_entities as $file_entity) {
+ file_move($file_entity, file_stream_wrapper_uri_normalize(file_uri_scheme($file_entity->uri) . '://' . $destination));
+ }
+ }
+ // Collect the subfolder operations.
+ $batch = array(
+ 'title' => t('Move root folder'),
+ 'operations' => array(),
+ 'finished' => 'media_browser_plus_move_root_folder_complete',
+ 'file' => drupal_get_path('module', 'media_browser_plus') . '/includes/media_browser_plus.folders.inc',
+ );
+
+ // Set the media root folder variable to the new destination.
+ $batch['operations'] = array();
+
+ // Move subfolders.
+ $root_subfolders = taxonomy_get_children($root_folder_term->tid);
+ foreach ($root_subfolders as $subfolder) {
+ $subfolder_source = media_browser_plus_construct_dir_path($subfolder);
+ $subfolder_destination = $destination . str_replace($source, '', $subfolder_source);
+ // Already takes care of multiple stream wrappers.
+ $batch['operations'] = array_merge($batch['operations'], media_browser_plus_move_subfolder($subfolder, $subfolder_source, $subfolder_destination));
+ }
+ batch_set($batch);
+}
+
+/**
+ * Finish-callback for the move root folder batch.
+ */
+function media_browser_plus_move_root_folder_complete($success, $results, $operations) {
+ if ($success) {
+ drupal_set_message(t('Successfully changed media root folder and all file URIs'));
+ }
+ else {
+ drupal_set_message(t('Error while changing media root folder'), 'error');
+ }
+}
+
+/**
+ * Helper function to move a subfolder - and update the related files.
+ *
+ * @param object $folder
+ * The _updated_ folder term. Is used to generate the destination.
+ * @param string $source
+ * The current path without scheme.
+ * @param string $destination
+ * The new path. Including the directory name but without scheme!
+ *
+ * @return array
+ * A list of batch operations to execute to finish the job.
+ */
+function media_browser_plus_move_subfolder($folder, $source, $destination) {
+ $operations = array();
+ foreach (media_get_local_stream_wrappers() as $scheme => $scheme_info) {
+ $source_path = file_stream_wrapper_uri_normalize($scheme . '://' . $source);
+ $destination_path = file_stream_wrapper_uri_normalize($scheme . '://' . $destination);
+ if ($source != $destination) {
+ // This will move all subfolders too. Thus we have to handle all child
+ // folder terms as well.
+ file_prepare_directory($destination_path, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ media_browser_plus_move_physical_folder($source_path, $destination_path);
+ }
+ // @todo This could move into the condition, but this way it's more stable.
+ // Update files in folder and subfolders get folders.
+ $folders = array($folder->tid);
+
+ // Fetch all sub-folders.
+ $sub_folders = taxonomy_get_tree($folder->vid, $folder->tid);
+ foreach ($sub_folders as $sub_folder) {
+ $folders[] = $sub_folder->tid;
+ }
+ $operations[] = array('media_browser_plus_folder_update_file_locations_batch', array($folders));
+ }
+
+ return $operations;
+}
+
+/**
+ * Batch function to move files to the location according the assigned folder.
+ *
+ * Adjust the file uri to match the path given by the assigned folder. If the
+ * uri is adjusted hook_file_move() is invoked.
+ * If the file isn't located in the related directory on the disk it's moved.
+ * The legacy path of the file is logged in $context['handled_directories'].
+ *
+ * @param array $folders
+ * A list of folder ids (term ids).
+ * @param array $context
+ * Batch context array.
+ */
+function media_browser_plus_folder_update_file_locations_batch($folders, &$context) {
+ $step_size = 25;
+
+ $file_query = new EntityFieldQuery();
+ $file_query
+ ->entityCondition('entity_type', 'file');
+ if (!empty($folders)) {
+ $file_query->fieldCondition('field_folder', 'tid', $folders, 'IN');
+ }
+
+ if (empty($context['sandbox'])) {
+ $context['sandbox']['progress'] = 0;
+ $files = $file_query->execute();
+ $context['sandbox']['max'] = (!empty($files['file'])) ? count($files['file']) : 0;
+ $context['local_stream_wrappers'] = media_get_local_stream_wrappers();
+ }
+ if (!isset($context['results'])) {
+ $context['results'] = array('success' => array(), 'errors' => array());
+ }
+
+ $file_query->range($context['sandbox']['progress'], $step_size);
+ $files = $file_query->execute();
+ $file_entities = array();
+ if (!empty($files['file'])) {
+ $file_entities = file_load_multiple(array_keys($files['file']));
+ }
+ // Checking media.
+ foreach ($file_entities as $file) {
+ // Only handle locale files with a folder id.
+ if (isset($context['local_stream_wrappers'][file_uri_scheme($file->uri)]) && isset($file->field_folder[LANGUAGE_NONE][0]['tid'])) {
+ // Update file path.
+ $source = clone $file;
+ $path = media_browser_plus_construct_dir_path(taxonomy_term_load($file->field_folder[LANGUAGE_NONE][0]['tid']));
+ $file->uri = file_stream_wrapper_uri_normalize(file_uri_scheme($file->uri) . '://' . $path . '/' . drupal_basename($file->uri));
+ // Check if the uri has changed.
+ if ($file->uri !== $source->uri) {
+ // Check if the source file still exists, if so move the file.
+ clearstatcache();
+ if (file_exists(drupal_realpath($source->uri))) {
+ $context['handled_directories'][drupal_dirname($source->uri)] = drupal_dirname($source->uri);
+ $destination = drupal_dirname($file->uri);
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ file_unmanaged_move($source->uri, $destination, FILE_EXISTS_RENAME);
+ }
+ // Save all the changes and inform other modules.
+ file_save($file);
+ // Inform modules that the file has been moved.
+ module_invoke_all('file_move', $file, $source);
+ }
+ }
+ }
+ // Increment progress but make sure start is not above max (for progress).
+ $context['sandbox']['progress'] = min($context['sandbox']['max'], ($context['sandbox']['progress'] + $step_size));
+ // Set other context values.
+ $context['message'] = t('Relocating files') . '...(' . $context['sandbox']['progress'] . '/' . $context['sandbox']['max'] . ') ';
+ $context['finished'] = 1;
+ if ($context['sandbox']['progress'] < $context['sandbox']['max']) {
+ $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+ }
+}
+
+/**
+ * Cut-paste a directory with its children into a new filesystem location.
+ *
+ * @param string $source
+ * The current path.
+ * @param string $destination
+ * The new path.
+ *
+ * @return bool
+ * TRUE on success.
+ */
+function media_browser_plus_move_physical_folder($source, $destination) {
+ $destination = drupal_realpath($destination);
+ $source = drupal_realpath($source);
+ $jail = drupal_realpath(variable_get('file_default_scheme', 'public') . '://');
+ $files = @scandir($source);
+ if ($files && count($files) > 2) {
+ $transfer = new FileTransferLocal($jail);
+ clearstatcache();
+ // We need to copy the children first and later handle the source folder
+ // since this is how FileTransferLocal works.
+ foreach ($files as $file) {
+ if (!in_array($file, array('.', '..'))) {
+ $source_path = $source . DIRECTORY_SEPARATOR . $file;
+ $copy_destination = $destination . DIRECTORY_SEPARATOR . $file;
+ if (is_file($source_path)) {
+ $transfer->copyFile($source_path, $copy_destination);
+ $transfer->removeFile($source_path);
+ }
+ else {
+ $transfer->copyDirectory($source_path, $copy_destination);
+ $transfer->removeDirectory($source_path);
+ }
+ }
+ }
+ // All stuff is moved to destination, delete the source now.
+ $transfer->removeDirectory($source);
+ }
+ else {
+ // The folder is empty so just delete and create the new one.
+ if (file_exists($source)) {
+ drupal_rmdir($source);
+ }
+ file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+ }
+ return TRUE;
+}
+
+
+/**
+ * Rebuilds the folder structure on the disk.
+ *
+ * All local files that have a folder id will be processed. If a file isn't
+ * located where it should be it's moved to the correct place.
+ * This will trigger hook_file_move() so that other modules can act.
+ * After all files are processed the legacy directories are deleted if they're
+ * empty.
+ *
+ * @see hook_file_move()
+ */
+function media_browser_plus_rebuild_folder_structure() {
+ // Prepare batch.
+ $batch = array(
+ 'title' => t('Rebuild folder structure'),
+ 'operations' => array(
+ array('media_browser_plus_rebuild_folder_structure_process', array()),
+ ),
+ 'finished' => 'media_browser_plus_rebuild_folder_structure_complete',
+ 'file' => drupal_get_path('module', 'media_browser_plus') . '/includes/media_browser_plus.folders.inc',
+ );
+ batch_set($batch);
+}
+
+/**
+ * Batch process of folder rebuild moves files and delete leftover directories.
+ *
+ * @see media_browser_plus_rebuild_folder_structure()
+ */
+function media_browser_plus_rebuild_folder_structure_process(&$context) {
+ // Reuse existing code to move the files.
+ media_browser_plus_folder_update_file_locations_batch(array(), $context);
+ // Cleanup empty directories.
+ if ($context['finished'] >= 1 && !empty($context['handled_directories'])) {
+ clearstatcache();
+ foreach ($context['handled_directories'] as $uri) {
+ $directory = drupal_realpath($uri);
+ if (is_dir($directory)) {
+ foreach (new RecursiveIteratorIterator(new SkipDotsRecursiveDirectoryIterator($directory), RecursiveIteratorIterator::CHILD_FIRST) as $filename => $file) {
+ if ($file->isDir()) {
+ @drupal_rmdir($filename);
+ }
+ elseif ($file->isFile()) {
+ // If there's a file left, don't delete the folder.
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Finish callback for the folder structure rebuild batch.
+ */
+function media_browser_plus_rebuild_folder_structure_complete($success, $results, $operations) {
+ if ($success) {
+ drupal_set_message(t('Successfully rebuild the folder structure'));
+ }
+ else {
+ drupal_set_message(t('Error while rebuilding folder structure'), 'error');
+ }
+}