There is no simple way to update the image of an existing media record.
The package appears to be written with the intent to never update the image of an existing media record. I'm not sure why this is the case, maybe there is a good reason for this I am missing.
Use Case:
An app with blog posts that have zero or more attached media records. The blog post editing ui has a list view of each media record attached displaying the file/image, title, and description of each media record (title and description are stored in media.custom_properties).
A user is editing a post with multiple images attached with titles and descriptions. There is a media record that they wish to update the image of but want to keep the title and description they have already written for it.
Building this list view using a front-end that makes changes via an async api becomes unusually difficult. You have a collection of media records on the front end using media.id as the unique identifier of each list item. It is easy to update all the data of an existing media record except the image/file. Abstracting the updating of an existing media item by creating a new one to replace it complicates syncing the data changes with the front end as the id of the media item has changed.
I'm very surprised no one has mentioned this case before.
After digging into the code I realize adding this would take some work. I would be happy to make a PR. Would the Spatie group be open to discussing how best implement this?
This is a reduced case of my current solution for updating the file of an existing media item.
I have not yet tackled triggering regeneration of the media records conversions.
namespace App\Models;
use Spatie\MediaLibrary\FileManipulator;
use Spatie\MediaLibrary\Media as BaseMedia;
use Spatie\MediaLibrary\Helpers\File;
class Media extends BaseMedia {
public function updateFile($newFile) {
$fileName = $newFile->getClientOriginalName();
$fileName = $this->sanitizeFileName($fileName);
$currentFileName = $this->file_name;
$path = $newFile->path();
$fileSystem = app(\Spatie\MediaLibrary\Filesystem\Filesystem::class);
$this->name = pathinfo($fileName, PATHINFO_FILENAME);
$this->file_name = $fileName;
$this->mime_type = File::getMimetype($path);
$this->size = filesize($path);
$fileSystem->removeFiles($this);
// overwrite current file keep old name
$fileSystem->copyToMediaLibrary($path, $this, false, $currentFileName);
// when this model is saved, the file will be renamed appropriately to $fileName via $media->file_name
}
public function setCustomProperties(array $properties) {
foreach ($properties as $key => $val) {
$this->setCustomProperty($key, $val);
}
}
protected function sanitizeFileName(string $fileName): string {
return str_replace(['#', '/', '\\'], '-', $fileName);
}
public function regenerate(){
/** @var FileManipulator $fileManipulator */
$fileManipulator = app(FileManipulator::class);
$fileManipulator->createDerivedFiles($this);
}
}
// usage in route
Route::post('media/{media}/update-file', function (Request $request, Media $media) {
$newFile = $request->file('new_file');
$media->updateFile($newFile);
});
Thank you for this code, but we're probably not going to add this feature to the package. If you want to replace a media item, just delete the old one and create a new one (with the newer files) and set its properties to the same values as the old media item.
Is there a reason why? I thought I provided a reasonable case.
I also think that ->replace($name = 'logo') would be useful
Hello Freek, I think it could be very useful to be able update a record since you want to include a media manager in your cms where you can update some infos, upload new file, etc.
(like in Wordpress to use a famous example ;)
@unstoppablecarl @canvural Please is there a way I can upload new image[s] to an existing model? In my situation, I created a Property form that accepts multiple property images which work well, but the problem is when trying to update that Property Model to accepts more image whenever the user clicks on update form, I get the same error as above.
Here is it for update function.
foreach ($request->file('property_photos', []) as $key => $file) {
$property->addMedia($file)
->preservingOriginal()
->toMediaCollection('property_image');
}
For this update, I want to add more images to the existing image in the Property Model without having to delete previous uploaded image
There is not a reasonable way to do it with this package. You have to delete and create.
Most helpful comment
Is there a reason why? I thought I provided a reasonable case.