Skip to content
Snippets Groups Projects
Commit c0c7fdef authored by codebymikey's avatar codebymikey Committed by Joachim Feltkamp
Browse files

Issue #3214405: Make use of the appropriate destination file

parent 614874f7
No related branches found
No related tags found
1 merge request!1Issue #3214405: Make use of the appropriate destination file
......@@ -5,16 +5,16 @@ namespace Drupal\file_update;
use Drupal\Core\Entity\EntityMalformedException;
use Drupal\Core\Entity\EntityStorageException;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\File\FileSystem;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Image\ImageFactory;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Core\Site\Settings;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\file\FileInterface;
use Drupal\file_update\Plugin\FileUpdate\FileUpdateManager;
use Drupal\Core\ProxyClass\File\MimeType\MimeTypeGuesser;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
/**
* Class FileUpdateService.
......@@ -61,28 +61,28 @@ class FileUpdateService {
/**
* Drupal\file\FileStorage definition.
*
* @var \Drupal\file\FileStorage
* @var \Drupal\file\FileStorageInterface
*/
protected $fileStorage;
/**
* Drupal\Core\File\FileSystem definition.
* Drupal\Core\File\FileSystemInterface definition.
*
* @var \Drupal\Core\File\FileSystem
* @var \Drupal\Core\File\FileSystemInterface
*/
protected $fileSystem;
/**
* Drupal\Core\Extension\ModuleHandler definition.
* Drupal\Core\Extension\ModuleHandlerInterface definition.
*
* @var \Drupal\Core\Extension\ModuleHandler
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Drupal\Core\ProxyClass\File\MimeType\MimeTypeGuesser definition.
* The MIME type guesser.
*
* @var \Drupal\Core\ProxyClass\File\MimeType\MimeTypeGuesser
* @var \Symfony\Component\Mime\MimeTypeGuesserInterface|\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface
*/
protected $mimeTypeGuesser;
......@@ -98,14 +98,14 @@ class FileUpdateService {
*
* @var \Drupal\file\FileInterface
*/
private $fileEntity;
protected $fileEntity;
/**
* File properties set on init service.
*
* @var array
*/
private $fileProps;
protected $fileProps;
/**
* Drupal\file_update\Plugin\FileUpdate\FileUpdateInterface definition.
......@@ -127,12 +127,12 @@ class FileUpdateService {
* Messenger service.
* @param \Drupal\Core\Image\ImageFactory $image_factory
* Image factory service.
* @param \Drupal\Core\File\FileSystem $file_system
* @param \Drupal\Core\File\FileSystemInterface $file_system
* File system service.
* @param \Drupal\file_update\Plugin\FileUpdate\FileUpdateManager $file_update_manager
* FileUpdate plugin manager.
* @param \Drupal\Core\ProxyClass\File\MimeType\MimeTypeGuesser $mime_type_guesser
* Mime type guesser service.
* @param \Symfony\Component\Mime\MimeTypeGuesserInterface|\Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mime_type_guesser
* The MIME type guesser.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
......@@ -143,9 +143,9 @@ class FileUpdateService {
LoggerChannelInterface $logger_channel,
MessengerInterface $messenger,
ImageFactory $image_factory,
FileSystem $file_system,
FileSystemInterface $file_system,
FileUpdateManager $file_update_manager,
MimeTypeGuesser $mime_type_guesser
$mime_type_guesser
) {
$this->currentUser = $current_user;
$this->entityTypeManager = $entity_type_manager;
......@@ -332,6 +332,7 @@ class FileUpdateService {
* Returns TRUE if operation was successful.
*/
public function updateFile($file, array $options) {
$this->resetFileEntity();
if ($this->initService($file)) {
// Move file.
if (isset($options['move_to']) && $options['move_to']) {
......@@ -347,6 +348,34 @@ class FileUpdateService {
return FALSE;
}
/**
* Reset the file and file prop field.
*/
protected function resetFileEntity() {
$this->fileEntity = NULL;
$this->fileProps = NULL;
}
/**
* Returns the current file entity.
*
* @return \Drupal\file\FileInterface|null
* The current file entity.
*/
public function getCurrentFileEntity() {
return $this->fileEntity;
}
/**
* Returns the current file props.
*
* @return array
* The current file props.
*/
public function getCurrentFileProps() {
return $this->fileProps;
}
/**
* Validates max resolution if file is an image.
*
......@@ -408,8 +437,8 @@ class FileUpdateService {
* @param string $filename
* A file name, path, path/file_name, uri.
*
* @return bool
* If operation was successful.
* @return string|bool
* The destination file, or false if the operation was unsuccessful.
*/
protected function moveFile($filename) {
$uri_new = $this->prepareNewUri($this->fileEntity, $filename);
......@@ -419,20 +448,63 @@ class FileUpdateService {
if ($uri_new != $uri_old) {
$dir = $this->prepareDirectory($uri_new);
if ($dir && $move_success = file_move($this->fileEntity, $uri_new)) {
$move_mode = Settings::get('file_update.move_mode', 'rename');
switch ($move_mode) {
case 'error':
$replace = FileSystemInterface::EXISTS_ERROR;
break;
case 'replace':
// NOTE: YOU MOST LIKELY DO NOT want to enable this option.
// Two file entities may not reference the same URI, so the entity
// returned by "file_move" in this mode may be changed to a different
// entity than the one passed in.
// In the situation that it creates a new entity while matching
// against an existing URI. It can lead to orphan entities, and the
// plugins will act on the "new" entity instead leading to unexpected
// behaviour.
// @todo investigate if there's an easy way to apply a replace without
// losing reference to the existing uuid.
/* $replace = FileSystemInterface::EXISTS_REPLACE; break; */
throw new \InvalidArgumentException('The replace option is not supported at the moment.');
default:
// Recommended: always create a new file in order to be uniquely
// identifiable.
$replace = FileSystemInterface::EXISTS_RENAME;
break;
}
if ($dir && $move_success = file_move($this->fileEntity, $uri_new, $replace)) {
try {
if ($move_success->save() == SAVED_UPDATED) {
$this->fileEntity = $move_success;
$this->messenger->addMessage($this->t('Moved image (%id): %old => %new', [
'%id' => $fid,
'%old' => $uri_old,
'%new' => $uri_new,
]));
$destination = $move_success->getFileUri();
if ($uri_new !== $destination) {
// Given that it's moving using FileSystemInterface::EXISTS_RENAME
// by default, the destination file is not guaranteed to be free.
// So log if a different file is being used instead.
$context = [
'%id' => $fid,
'%old' => $uri_old,
'%new' => $uri_new,
'%dest' => $destination,
];
$this->messenger->addWarning($this->t('Moved image (%id): %old => %dest. %new already exists.', $context));
$this->loggerChannel->warning('Moved image (%id): %old => %dest. %new already exists.', $context);
}
else {
$this->messenger->addMessage($this->t('Moved image (%id): %old => %destination', [
'%id' => $fid,
'%old' => $uri_old,
'%dest' => $destination,
]));
}
foreach ($this->plugins as $plugin) {
$plugin->updateUri($uri_new);
$plugin->updateUri($destination);
}
return TRUE;
return $destination;
}
}
catch (\Exception $exception) {
......@@ -470,8 +542,8 @@ class FileUpdateService {
$path = explode('/', $uri);
/* $file_name = */ array_pop($path);
$path = implode('/', $path);
$dir = $this->fileSystem->prepareDirectory($path, FileSystem::CREATE_DIRECTORY);
$write = $this->fileSystem->prepareDirectory($path, FileSystem::MODIFY_PERMISSIONS);
$dir = $this->fileSystem->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY);
$write = $this->fileSystem->prepareDirectory($path, FileSystemInterface::MODIFY_PERMISSIONS);
return ($dir && $write);
}
......@@ -504,7 +576,14 @@ class FileUpdateService {
if (preg_match('/\.[a-zA-Z0-9]{2,7}$/', $filename) == 1) {
// It's not just a path that ends with a "/".
$mime_guess = $this->mimeTypeGuesser->guess($filename);
if ($this->mimeTypeGuesser instanceof MimeTypeGuesserInterface) {
$mime_guess = $this->mimeTypeGuesser->guessMimeType($filename);
}
else {
// https://www.drupal.org/node/3133341
// Deprecated in D9.1.
$mime_guess = $this->mimeTypeGuesser->guess($filename);
}
if ($mime_guess == $file_entity->getMimeType()) {
$new_filename_frags = explode('.', $filename);
$ending = array_pop($new_filename_frags);
......@@ -577,19 +656,4 @@ class FileUpdateService {
}
}
/**
* Check if uri is valid.
*
* @param $uri
* The URI to check.
*
* @return bool
* If uri is valid.
*/
public function isValidUri($uri) {
/** @var StreamWrapperManager $stream_wrapper_manager */
$stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
return $stream_wrapper_manager->isValidScheme($uri);
}
}
......@@ -185,7 +185,15 @@ class FileUpdateForm extends FormBase {
}
$fid = $form_values['file_id'];
if (isset($form_values['file_id']) && $value) {
if (!$this->updateService->prepareNewUri($fid, $value)) {
if ($new_uri = $this->updateService->prepareNewUri($fid, $value)) {
if (file_exists($new_uri)) {
// Avoid unnecessary duplicates/ filename appends.
$form_state->setErrorByName($key, $this->t('The destination URI %destination already exists.', [
'%destination' => $new_uri,
]));
}
}
else {
$form_state->setErrorByName($key, $this->t('The entered URI is not valid.'));
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment