A possible solution I could imagine would be overriding getDestinationFilename() of the file system service.
Thus, you could create a custom module with a service provider class for altering the definition of the Core file_system
service to use your adapted version.
In your adapted method, you could check the destination path of the target file and add your logic (e.g., renaming existing files, rather than the newly added file) before returning the destination file name.
A quick wrap-up:
- Create a custom module 'profile_pic_path'
- Create a
ProfilePicPathServiceProvider.php
class file in its src
folder. If you use a different module name, this class name should be constructed using the camel case module name and added ServiceProvider
suffix:
<?php
namespace Drupal\profile_pic_path;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
use Drupal\Core\DependencyInjection\ServiceProviderInterface;
/**
* {@inheritdoc}
*
* Used to alter the container `file_system`
* service definition.
*/
class ProfilePicPathServiceProvider extends ServiceProviderBase implements ServiceProviderInterface {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
$service_def = $container->getDefinition('file_system');
// Use our custom class `CustomFileSystem`.
$service_def->setClass(CustomFileSystem::class);
}
}
- Create your file system class override
CustomFileSystem.php
in the src
folder:
<?php
namespace Drupal\profile_pic_path;
use Drupal\Core\File\FileSystem;
use Drupal\Core\File\FileSystemInterface;
/**
* {@inheritdoc}
*
* Example override of the core `file_system`
* method `getDestinationFilename()`.
*/
class CustomFileSystem extends FileSystem implements FileSystemInterface {
/**
* {@inheritdoc}
*
* Renames existing files to a new file name
* rather than renaming new files while
* keeping the old files.
*/
public function getDestinationFilename($destination, $replace) {
$target_destination = parent::getDestinationFilename($destination, $replace);
// Add your logic to check, whether it's a profile picture
// and possibly to remove existing files/file entities/alter
// the destination path/or rename existing files to the
// suggested new file name while returning the original file
// destination here. An example:
if (
// Whether the target file exists.
file_exists($destination)
// Whether file renaming has been requested.
&& $replace === FileSystemInterface::EXISTS_RENAME
) {
// Rename the existing file to the new
// name returned by the core method.
$this->move($destination, $target_destination);
// Update any existing file entities using
// the existing file with the new URI.
/** @var \Drupal\file\FileInterface[] $files */
$files = \Drupal::entityTypeManager()
->getStorage('file')
->loadByProperties(['uri' => $destination]);
if ($files) {
foreach ($files as $file) {
$file->setFileUri($target_destination);
$file->save();
}
}
// Return the original destination.
return $destination;
}
// Return the destination determined by the
// core method.
return $target_destination;
}
}