-
Hi, I'm using Backpack with Laravel Vapor. I have successfully implemented most of the Lambda changes. However, I'm facing difficulty adapting the image field blade to work in a serverless style, as explained here: https://docs.vapor.build/1.0/resources/storage.html#file-uploads and here: https://www.youtube.com/watch?v=iKjpy3USuXs&ab_channel=Laravel. I have had success through the php to store in s3, locally and on lambda, however keen to move to pure s4 to avoid any upload limitations etc. Has anyone else encountered this issue and managed to find a solution? Note i have installed but then hit a wall |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 2 replies
-
Hey @malek77z The main difference in the image field is that it is not a I am sorry that I can't help with anything more specific, maybe someone else faced the same issue as you and can provide some more insights about it. Cheers |
Beta Was this translation helpful? Give feedback.
-
@pxpm thanks for helping. I actually managed to work it out and just in case its useful here is how i achieved it. Note that you will have to have Vapor installed and run Then I copied and updated the image blade file like so: (note the tmp_disk option)
Also, here is an image trait I have made to do the storing, it will work with normal local files, s3 buckets and tmp vapor folders <?php
namespace App\Traits;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
trait ImageTrait
{
public function setImageUrlAttribute($value, $attributeName="image_url")
{
$attribute_name = $attributeName;
$disk = config('features.use_s3_images') ? 's3' : 'public';
// remove if now none
if (empty($value)) {
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = null;
}
if (Str::startsWith($value, 'data:image')) {
$image = Image::make($value)->encode('jpg', 90);
$destination_path = $this->getImageDestinationPath($attribute_name);
$filename = $this->getImageFilename($value, $attribute_name);
Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream(), 'public');
// remove if different from saves
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = Storage::disk($disk)->url($destination_path.'/'.$filename);
} elseif (!empty($value)) {
// This can either be a URL that we want to store, or a tmp S3 KEY we want to move permanently and store
// The temp S3 KEY will look like this: tmp/a866dc90-b2e2-494b-8fcc-bc729b047685
// First we want to check for that
// check for temp S3 KEY
if(Str::startsWith($value, 'tmp/')) {
// we have a temp S3 URL, lets move it to the right place
$destination_path = $this->getImageDestinationPath($attribute_name);
$filename = $this->getImageFilename($value, $attribute_name);
$new_path = $destination_path.'/'.$filename;
Storage::disk($disk)->copy($value, $new_path);
Storage::disk($disk)->setVisibility($new_path, 'public');
// delete the tmp file option, not needed really as we will do clean up
config('features.delete_tmp_s3_files') ? Storage::disk($disk)->delete($value) : null;
// remove if different from saves
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = Storage::disk($disk)->url($new_path);
} else {
// we have a URL, lets just store it
$this->attributes[$attribute_name] = $value;
}
}
}
// trash a S3 image
public function trashImage($image_location)
{
// image location will be a whole URL, so we need to parse it and get the S3 true path
$disk = config('features.use_s3_images') ? 's3' : 'public';
$image_location = parse_url($image_location, PHP_URL_PATH);
// Break down the image path into directory, filename, and extension
$image_pathinfo = pathinfo($image_location);
// Construct the new image location by adding the model's ID to the start of the filename
$new_image_location = 'trash/'. $image_pathinfo['dirname'] . '/' . $this->id . '_' . $image_pathinfo['basename'];
// Move the file to the new location within the "trash" directory
Storage::disk($disk)->move($image_location, $new_image_location);
// Set the visibility of the trashed file to 'private'
Storage::disk($disk)->setVisibility($new_image_location, 'private');
}
protected function getImageDestinationPath($attribute_name)
{
// Define the specific destination path logic for each model
$year = date('Y');
$month = date('m');
$day = date('d');
// get the model name
$model_name = strtolower(class_basename($this));
return "/$model_name/$year/$month/$day/$attribute_name";
}
protected function getImageFilename($value, $attribute_name)
{
// Define the specific filename logic for each model
$timestamp = time();
return $attribute_name . '_' . "$timestamp" . '_' . md5($value.$timestamp) . '.jpg';
}
} also note, in the controller, I have had to add the following to make sure the correct permissions are set. Im sure there is a better way.
Not massively tested, but seems to work well. I hope that helps someone do the Vapor move. |
Beta Was this translation helpful? Give feedback.
-
Sorry, new to github, reposting the imageTrait in code tags <?php
namespace App\Traits;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Intervention\Image\ImageManagerStatic as Image;
trait ImageTrait
{
public function setImageUrlAttribute($value, $attributeName="image_url")
{
$attribute_name = $attributeName;
$disk = config('features.use_s3_images') ? 's3' : 'public';
// remove if now none
if (empty($value)) {
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = null;
}
if (Str::startsWith($value, 'data:image')) {
$image = Image::make($value)->encode('jpg', 90);
$destination_path = $this->getImageDestinationPath($attribute_name);
$filename = $this->getImageFilename($value, $attribute_name);
Storage::disk($disk)->put($destination_path.'/'.$filename, $image->stream(), 'public');
// remove if different from saves
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = Storage::disk($disk)->url($destination_path.'/'.$filename);
} elseif (!empty($value)) {
// This can either be a URL that we want to store, or a tmp S3 KEY we want to move permanently and store
// The temp S3 KEY will look like this: tmp/a866dc90-b2e2-494b-8fcc-bc729b047685
// First we want to check for that
// check for temp S3 KEY
if(Str::startsWith($value, 'tmp/')) {
// we have a temp S3 URL, lets move it to the right place
$destination_path = $this->getImageDestinationPath($attribute_name);
$filename = $this->getImageFilename($value, $attribute_name);
$new_path = $destination_path.'/'.$filename;
Storage::disk($disk)->copy($value, $new_path);
Storage::disk($disk)->setVisibility($new_path, 'public');
// delete the tmp file option, not needed really as we will do clean up
config('features.delete_tmp_s3_files') ? Storage::disk($disk)->delete($value) : null;
// remove if different from saves
if (isset($this->{$attribute_name}) && !empty($this->{$attribute_name})) {
$this->trashImage($this->{$attribute_name});
}
$this->attributes[$attribute_name] = Storage::disk($disk)->url($new_path);
} else {
// we have a URL, lets just store it
$this->attributes[$attribute_name] = $value;
}
}
}
// trash a S3 image
public function trashImage($image_location)
{
// image location will be a whole URL, so we need to parse it and get the S3 true path
$disk = config('features.use_s3_images') ? 's3' : 'public';
$image_location = parse_url($image_location, PHP_URL_PATH);
// Break down the image path into directory, filename, and extension
$image_pathinfo = pathinfo($image_location);
// Construct the new image location by adding the model's ID to the start of the filename
$new_image_location = 'trash/'. $image_pathinfo['dirname'] . '/' . $this->id . '_' . $image_pathinfo['basename'];
// Move the file to the new location within the "trash" directory
Storage::disk($disk)->move($image_location, $new_image_location);
// Set the visibility of the trashed file to 'private'
Storage::disk($disk)->setVisibility($new_image_location, 'private');
}
protected function getImageDestinationPath($attribute_name)
{
// Define the specific destination path logic for each model
$year = date('Y');
$month = date('m');
$day = date('d');
// get the model name
$model_name = strtolower(class_basename($this));
return "/$model_name/$year/$month/$day/$attribute_name";
}
protected function getImageFilename($value, $attribute_name)
{
// Define the specific filename logic for each model
$timestamp = time();
return $attribute_name . '_' . "$timestamp" . '_' . md5($value.$timestamp) . '.jpg';
}
} |
Beta Was this translation helpful? Give feedback.
-
Thanks for providing the code example @malek77z I took the liberty of editing your answer and added triple backticks (```php) then your code, instead of the simple tick (`) Here is a good guide on github markdown: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code-and-syntax-highlighting Cheers |
Beta Was this translation helpful? Give feedback.
-
I'm closing this issue due to inactivity. If you need further assistance or have additional questions, feel free to reopen this issue or create a new one. We're here to help! |
Beta Was this translation helpful? Give feedback.
@pxpm thanks for helping. I actually managed to work it out and just in case its useful here is how i achieved it.
Note that you will have to have Vapor installed and run
npm install --save-dev laravel-vapor
added a policy file and a few other steps that can be found here -> https://docs.vapor.build/1.0/resources/storage.html#file-uploads
Then I copied and updated the image blade file like so: (note the tmp_disk option)
Also, it tries to do Vapor.store on the form submit, then submit again.. I have not tested but i imagine it will do one by one until all done if a few images... im sure i have missed edge cases, one being on form fail and not being about to see the /tmp/ file in the s3 buc…