I am using laravel for a project i am making.
So i want that users can only create 30 products, and if they have more then 30 products, they cant create more products until they have removed some. What do i have to add in my code so that they cant add more products.
My Product controller
public function store(Request $request)
{
//check if user has more then 30 products
$product = Product::create($request->all());
$productPhotos = [];
$photos = $request->post('photo');
if (count($photos) <= 5) {
foreach (range(1, $photos) as $i) {
foreach ($photos as $imageData) {
$bcheck = explode(';', $imageData);
if (count($bcheck) > 1) {
list($type, $imageData) = explode(';', $imageData);
list(, $extension) = explode('/', $type);
list(, $imageData) = explode(',', $imageData);
$fileName = uniqid() . '.' . $extension;
$imageData = base64_decode($imageData);
Storage::put("public/products/$fileName", $imageData);
$imagePath = ('storage/products/' . $fileName);
$productPhotos[] = ProductPhoto::create([
'product_id' => $product->id,
'path' => $imagePath
]);
}
}
}
} else {
return response()->json("You cant add any photo's to your product", 400);
}
return response()->json([$product, $productPhotos], 201);
}
if i need to send some more code, let me know.
Thx in advance.
FINAL CODE:
$totalProduct = Product::where('supplier_id', $request->user()->Supplier->id)->count();
if ($totalProduct < 30){
$product = Product::create($request->all());
$productPhotos = [];
$photos = $request->post('photo');
if (count($photos)) {
foreach ($photos as $i => $imageData) {
if ($i >= 5) {
continue;
}
$bcheck = explode(';', $imageData);
if (count($bcheck) > 1) {
list($type, $imageData) = explode(';', $imageData);
list(, $extension) = explode('/', $type);
list(, $imageData) = explode(',', $imageData);
$fileName = uniqid() . '.' . $extension;
$imageData = base64_decode($imageData);
Storage::put("public/products/$fileName", $imageData);
$imagePath = ('storage/products/' . $fileName);
$productPhotos[] = ProductPhoto::create([
'product_id' => $product->id,
'path' => $imagePath
]);
}
}
}
return response()->json([$product, $productPhotos], 201);
} else{
return response()->json("you have to much products", 201);
}
}
User Model
public function projects()
{
return $this->hasMany('App\Project', 'id', 'user_id');
}
Project Model
public function users()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
Controller to Add projects
public function store(Request $request)
{
$totalCreatedProjects = $request->user()->products->count();
if ($totalCreatedProjects < 30) {
`Your code to add projects here`
}
`Your code to alert maximum projects achieved here`
}
This example assumed:
1. Your users are authenticated;
2. You created a database relationship 1 to many between Projects and Users;
Notes: When you compare to the amount of projects that exist and the number you wish to hold the creation instead of proceeding, this should be a service.
The number should be a constant with a proper semantic so other developers understand what you are trying to achieve
You can use this:
public function store(Request $request)
{
if($request->user()->products->count() < 30) {
//Add product
...
}else{
return redirect()->back();
}
}
public function store(Request $request)
{
//check if user has more then 29 products
if ($request->user()->products->count() >= 30) {
return response()->json("You cant add more then 30 products", 400);
}
// Your code...
In User Model Add
public function canAddNewProduct()
{
return $this->products->count() < 30;
}
In Controller
Auth::guard('web')->user()->canAddNewProduct()
Better way of doing is make a new middleware and use
return Auth::guard('web')->user()->canAddNewProduct() ? true : false
to protect the routes
Related
I'm building an API with Laravel 8 and I have posts and images table with polymorphic relation
So I want to upload multiple images and I'm doing it in postman, And when I upload images and enter posts fields with values, like this:
as you can see, I have an error in my foreach($files as $file)
ErrorException: Invalid argument supplied for foreach()
(In headers part Content-Type has multipart/form-data value )
So I think my problem is in store() method in postController ,
The codes :
post tables :
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('category_id');
$table->unsignedBigInteger('user_id');
$table->string('title');
$table->longText('body');
$table->string('video')->nullable();
$table->string('study_time');
$table->integer('likes')->nullable();
$table->tinyInteger('status')->nullable()->comment('status is 1 when a post is active and it is 0 otherwise.')->nullable();
$table->text('tags')->nullable();
$table->foreign('category_id')->references('id')->on('categories');
$table->foreign('user_id')->references('id')->on('users');
});
and my image table :
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->integer('imageable_id');
$table->string('imageable_type');
$table->string('url');
$table->timestamps();
});
and the post model :
.
.
.
.
public function image(){
return $this->morphOne(Image::class , 'imageable');
}
and my image model :
protected $fillable = [
'url'
];
public function imageable(){
return $this->morphTo();
}
and my store() method in postController :
public function store(Request $request )
{
$post = new Post;
$post->category_id = $request->get('category_id');
$post->title = $request->get('title');
$post->body = $request->get('body');
$post->study_time = $request->get('study_time');
$post->tags = $request->get('tags');
$post->user_id = JWTAuth::user()->id;
$tags = explode(",", $request->tags);
$post->tag($tags);
$allowedfileExtension=['pdf','jpg','png'];
$files = $request->file('fileName');
foreach ($files as $file) {
$extension = $file->getClientOriginalExtension();
$check = in_array($extension, $allowedfileExtension);
if($check) {
foreach($request->fileName as $mediaFiles) {
$url = $mediaFiles->store('public/images');
//store image file into directory and db
$image = new Image();
$image->url = $url;
}
}
else {
return response()->json(['invalid_file_format'], 422);
}
}
$post->image()->save($image);
$post->save();
return response()->json($post , 201);
}
thank you for your help :}
$files = $request->file('fileName');
... is returning null in your case, done you are not posting fileName, you use url.
If you would have validated your incoming data you would have received a validation errors 6 because of this. So: always validate incoming d data. Not only to catch errors like this, also b for security reasons.
public function store(Request $request)
{
if ($this->getErrorIfAny($request->all(), $this->ruls)) {
return $this->getErrorIfAny($request->all(), $this->ruls);
}
if (!$request->hasFile('image_url')) {
return response($this->getResponseFail(trans('my_keywords.uploadFileNotFound'), false), 400);
}
$allowedfileExtension = ['jpg', 'png', 'jpeg'];
$files = $request->file('image_url');
$number_photos_upload = count($files);
$pictures_available_upload = array();
for ($i = 0; $i < count($files); $i++) {
$extension = $files[$i]->getClientOriginalExtension();
$check = in_array($extension, $allowedfileExtension);
if ($check) {
$pictures_available_upload[$i] = $files[$i];
}
}
$number_images_success_uploded = 0;
$images_urls = array();
for ($i = 0; $i < count($pictures_available_upload); $i++) {
$image = $pictures_available_upload[$i];
$path = config('paths.storage_path') .
$image->store(config('paths.store_image_path'), 'public');
//store image file into directory and db
$store_images = new StoreImages();
$store_images['store_id'] = $request['store_id'];
$store_images['image_url'] = $path;
$result = $store_images->save();
if ($result) {
$images_urls[$i] = $path;
$number_images_success_uploded = $number_images_success_uploded + 1;
}
}
if ($number_images_success_uploded == 0) {
return response($this->getResponseFail(trans('my_keywords.invalidFileFormat'), false), 422);
} else {
$data = [
'store_id' => (int) $request['store_id'],
'number_photos_upload' => $number_photos_upload,
'number_images_success_uploded' => $number_images_success_uploded,
'images' => $images_urls,
];
return response($this->getResponse(__('my_keywords.operationSuccessfully'), true, $data), 200);
}
}
I am working with Laravel 7 trying to delete multiple images from my app. When I hit the delete button, the images are removed successfully from the show.blade.php as well as from the database. However, they are still in my storage on my local disk. I am storing my images in storage/app/public/upload as well as the symlink pointing to storage/upload in the public directory under app. I have tried a variety of ways to get it to delete but nothing has been fruitful. I have my one to many relationships set up in my models which I will show below. I need this to work under three circumstances such as if there is no image, one image or many images. I am using Laravel Resources for my routing and so my TaskController.php only has one destroy method.
Here is the code I have so far:
Models -
Image.php (relevant functions only - Storage and Task classes imported at top)
public function task()
{
return $this->belongsTo('App\Task', 'task_id');
// return $this->belongsTo(Task::class);
}
public static function boot()
{
parent::boot();
self::deleting(function ($images) {
Storage::delete(Storage::path($images['name']));
});
}
Task.php (relevant code only - Storage, File and Image classes imported at top)
public function images()
{
// return $this->hasMany('App\Image');
return $this->hasMany(Image::class);
}
public static function boot()
{
parent::boot();
self::deleting(function ($task) {
foreach ($task->images ?: [] as $image) {
$image->delete();
}
});
}
Controller
TasksController.php (store, show, update and destroy)
public function store(Request $request)
{
$this->validate($request, [
'task_name' => 'required',
'task_description' => 'required',
]);
// Create Task
$user = Auth::user();
$task = new Task();
$data = $request->all();
$task->user_id = $user->id;
$task = $user->task()->create($data);
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files ?: [] as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ', '-', $name);
$file->storeAs('public/upload', $name);
$task->images()->create(['name' => $name]);
$images = new Image;
$images->name = $name;
}
}
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->task_status;
$task->save();
return redirect('/home')->with('success', 'Task Created');
}
public function update(Request $request, $id)
{
$this->validate($request, [
'task_name' => 'required',
'task_description' => 'required',
]);
$task = Task::find($id);
$task->task_name = $request->input('task_name');
$task->task_description = $request->input('task_description');
$task->task_priority = $request->input('task_priority');
$task->task_assigned_by = $request->input('task_assigned_by');
$task->task_assigned_to = $request->input('task_assigned_to');
$task->task_to_be_completed_date = $request->input('task_to_be_completed_date');
$task->task_notes = $request->input('task_notes');
$task->task_status = $request->input('task_status');
if ($request->hasFile('images')) {
$files = $request->file('images');
foreach ($files ?: [] as $file) {
$name = time() . '-' . $file->getClientOriginalName();
$name = str_replace(' ', '-', $name);
$file->storeAs('public/upload', $name);
$task->images()->create(['name' => $name]);
$images = new Image;
$images->name = $name;
}
}
$task->save();
return redirect('/home')->with('success', 'Task Updated');
}
public function show($id)
{
$task = Task::find($id);
return view('tasks.show')->with('task', $task);
}
public function destroy($id)
{
$task = Task::findOrFail($id);
$images = Image::find($id);
$images = explode(',', $images['name']);
foreach ($images as $image) {
// $path = 'storage/app/public/upload/' . $image;
if (file_exists('../storage/app/public/upload/' . json_decode($image, true)['name'])) {
// print_r('file found');
// unlink('../storage/app/public/upload/' . base64_decode($image, true)['name']);
// dd('../storage/app/public/upload/' . json_decode($image, true)['name']);
// File::delete('../storage/app/public/upload/' . json_decode($image, true)['name']);
dd('../storage/app/public/upload/' . $task['image']);
File::delete('../storage/app/public/upload/' . json_decode($image, true)['name'] . $task['images']);
} else {
print_r('no sirve ' . __DIR__ . ' ' . $image . var_dump($image));
}
// dd($path);
// if (File::exists($path)) {
// File::delete($path);
// }
}
// $task->delete();
return redirect('home')->with('success', 'Task Deleted');
}
I have left some commented code included so you can see what I have tried. If I am missing anything, please let me know and I will edit my question.
Thank you in advance for your help. I have been stuck on this for a week.
EDIT
I have changed my destroy function. It still does not delete the files from the disk. Here is the function:
public function destroy($id)
{
// $task = Task::findOrFail($id);
$task = Task::with('images')->findOrFail($id);
// $images = Image::find($id);
// $images = $task->images($id)->get();
foreach ($task->images as $image) {
// dd(storage_path('app/public/upload/' . $image['name']));
Storage::delete(storage_path('app/public/upload/' . $image->name));
}
$task->images()->delete();
$task->delete();
return redirect('home')->with('success', 'Task Deleted');
}
I ended up calling the public folder for the delete function using Storage::disk('public')->delete('upload/' . $image->name);
That in the end helped me to delete the files from my disk. I hope this helps anyone who faces the same issue. Thank you Alzafan Christian for your help in this. You led me in the right direction.
Hi i'm using a form to create a new product and send the info to the controller and save it into the database, the form does send the data because I can see it when I do a Log inside the controller and the info is there, I don't understand why it's not being saved into the database?
In this example the data I've added to the product is minimal but there could be more like prices and countries, along with the stuff inside the store function like tags and sizes.
This is the complete store function in the controller
public function store(ProductSaveRequest $request)
{
DB::beginTransaction();
$product = new Product;
$product->fill($request->all());
$file = $request->file('image');
if ($file) {
$file = $request->file('image');
$filename = Uuid::uuid() . '.' . $file->getClientOriginalExtension();
$file->move('img/products', $filename);
$product->image = 'img/products/' . $filename;
}
$product->save();
Log::info($product);
if (!empty($request->get('prices'))) {
$prices = array_map(function ($item) use ($product) {
$item['product_id'] = $product->id;
return $item;
}, $request->get('prices'));
CountryProduct::insert($prices);
}
if ($request->has('tags')) {
$product->tags()->sync($request->get('tags'));
}
if ($request->has('sizes')) {
$product->sizes()->sync($request->get('sizes'));
}
if ($request->has('categories')) {
$productCategories = [];
foreach ($request->get('categories') as $item) {
if (key_exists('category_name', $item)) {
$category = Category::where('name', $item['category_name'])
->first();
} else if (key_exists('category_id', $item)) {
$category = Category::findOrFail($item['category_id']);
}
if (empty($category)) {
$category = new Category;
$category->name = $item['category_name'];
}
$category->type = $item['type'];
$category->save();
if (!empty($item['fields'])) {
foreach ($item['fields'] as $fieldItem) {
if (key_exists('field_name', $fieldItem)) {
$field = Field::where('name', $fieldItem['field_name'])
->first();
} else if (key_exists('field_id', $fieldItem)) {
$field = Field::findOrFail($fieldItem['field_id']);
}
if (empty($field)) {
$field = new Field;
$field->name = $fieldItem['field_name'];
$field->category_id = $category->id;
}
$field->save();
$productCategories[] = [
"field_id" => $field->id,
"category_id" => $category->id,
"product_id" => $product->id,
"value" => $fieldItem['value']
];
}
}
if (count($productCategories) > 0) {
ProductField::insert($productCategories);
}
ExportationFactor::insert($product);
}
$product->save();
DB::commit();
return $product;
}
}
This is the Log.info
local.INFO: {"discount":"1","code":"123","sku":"123","description_spanish":"123","description_english":"123","brand_id":"2","id":591}
The current output is that I get a success action and it says it has been successfully added but when I go look it's not there.
Put your commit method outside the last if condition.
public function store(ProductSaveRequest $request)
{
DB::beginTransaction();
$product = new Product;
$product->fill($request->all());
$file = $request->file('image');
if ($file) {
$file = $request->file('image');
$filename = Uuid::uuid() . '.' . $file->getClientOriginalExtension();
$file->move('img/products', $filename);
$product->image = 'img/products/' . $filename;
}
$product->save();
Log::info($product);
if (!empty($request->get('prices'))) {
$prices = array_map(function ($item) use ($product) {
$item['product_id'] = $product->id;
return $item;
}, $request->get('prices'));
CountryProduct::insert($prices);
}
if ($request->has('tags')) {
$product->tags()->sync($request->get('tags'));
}
if ($request->has('sizes')) {
$product->sizes()->sync($request->get('sizes'));
}
if ($request->has('categories')) {
$productCategories = [];
foreach ($request->get('categories') as $item) {
if (key_exists('category_name', $item)) {
$category = Category::where('name', $item['category_name'])
->first();
} else if (key_exists('category_id', $item)) {
$category = Category::findOrFail($item['category_id']);
}
if (empty($category)) {
$category = new Category;
$category->name = $item['category_name'];
}
$category->type = $item['type'];
$category->save();
if (!empty($item['fields'])) {
foreach ($item['fields'] as $fieldItem) {
if (key_exists('field_name', $fieldItem)) {
$field = Field::where('name', $fieldItem['field_name'])
->first();
} else if (key_exists('field_id', $fieldItem)) {
$field = Field::findOrFail($fieldItem['field_id']);
}
if (empty($field)) {
$field = new Field;
$field->name = $fieldItem['field_name'];
$field->category_id = $category->id;
}
$field->save();
$productCategories[] = [
"field_id" => $field->id,
"category_id" => $category->id,
"product_id" => $product->id,
"value" => $fieldItem['value']
];
}
}
if (count($productCategories) > 0) {
ProductField::insert($productCategories);
}
ExportationFactor::insert($product);
}
}
DB::commit();
return $product;
}
In the first line of the method, you begin a database transaction.
But you only commit the database transaction
if ($request->has('categories')) {
I want to save the same data with 365 records within one table. I'm new to Laravel.
I've tried with replicate() but was unsuccessful. I tried this on the Apache server and used Laravel5.7.
my controller
public function price_save(Request $request) {
$price=new Price();
$price->price=$request->price;
$price->extra_bed=$request->extra_bed;
$price->room_id=$request->room;
$id=$request->room;
$price = Price::find($id);
if(null !== $price){
$new = $price->replicate();
if(null !== $new){
$new->push();
// $price->save();
}
I am NOT sure about your code, But you can customize it as per your needs, To just get idea :
$model = User::find($id);
$model->load('invoices');
$newModel = $model->replicate();
$newModel->push();
foreach($model->getRelations() as $relation => $items){
foreach($items as $item){
unset($item->id);
$newModel->{$relation}()->create($item->toArray());
}
}
Credits
public function price_save(Request $request, int $id)
{
if ($id > 365) {
return;
}
$price = new Price();
$price->price = $request->price;
$price->extra_bed = $request->extra_bed;
$price->room_id = $request->room;
$price->save();
$existing = Price::find($request->room);
if ($existing) {
$request = $request->replace([
'price' => $price->price,
'extra_bed' => $price->extra_bed,
'room_id' => $price->room,
]);
}
return price_save($request, $id++);
}
I have the simple app below. I'm turning off query logging in Laravel, I'm unsetting where possible, yet this function will only process about 800 records before I'm out of RAM on my 2GB Linode. I know I'm asking a lot of you guys but I can't seem to see where I'm leaking memory.
There are really only two major steps.
Step 1 - Move records from a temp table to production
class ListingMigrator
{
public function __construct($tempListing, $feed)
{
$this->tempListing = $tempListing;
$this->listing = $this->listingInstance();
$this->feed = $feed;
}
public static function migrateListing($listing, $feed)
{
$instance = new static($listing, $feed);
return $instance->migrate();
}
public function migrate()
{
$this->addExternalData();
$this->populateListing();
$this->processPhotos();
$this->deleteTempListing();
}
private function listingInstance()
{
DB::connection()->disableQueryLog();
$listing = Listing::findByMud($this->tempListing->matrix_unique_id);
return $listing ?: new Listing;
}
private function processPhotos()
{
$retsApi = new RetsFeedApi($this->feed);
/* Initialize Object */
$rets = $retsApi->findMostRecent();
$photos = $rets->getPhotosForListing($this->listing->matrix_unique_id);
foreach ($photos as $photo)
{
$uploader = new PhotoProcessor($this->listing, $photo);
$uploader->process();
}
}
private function populateListing()
{
DB::connection()->disableQueryLog();
$this->listing->fill($this->tempListing->toArray());
$this->listing->imported_at = $this->tempListing->created_at;
$this->listing->board = $this->tempListing->board;
return $this->listing->save();
}
private function addExternalData()
{
// Get Google lattitude and longitude
$googlecoords = getGoogleMapInfo($this->tempListing->FullAddress, $this->tempListing->City);
$this->listing->GoogleLat = $googlecoords['GoogleLat'];
$this->listing->GoogleLong = $googlecoords['GoogleLong'];
// Add or update the Subdivision Table (helper function)
$subdivisiondata = SubdivisionUpdate($this->tempListing->board, $this->tempListing->SubCondoName, $this->tempListing->Development);
$this->listing->SubdivisionID = $subdivisiondata['id'];
}
private function deleteTempListing()
{
return $this->tempListing->delete();
}
}
Step 2 - Download photos and reupload to Amazon S3
class PhotoProcessor
{
public function __construct(Listing $listing, $photoData)
{
$this->bucket = 'real-estate-listings';
$this->s3 = App::make('aws')->get('s3');
$this->tempFileName = 'app/storage/processing/images/retsphotoupload';
$this->photoData = $photoData;
$this->listing = $listing;
$this->photo = new RetsPhoto;
}
public function process()
{
$this->storeTempFile();
$this->storeFileInfo();
$this->buildPhoto();
$success = $this->pushToS3();
// if Result has the full URL or you want to build it, add it to $this->photo
DB::connection()->disableQueryLog();
$this->listing->photos()->save($this->photo);
$this->removeTempFile();
unset ($this->photoData);
return $success;
}
private function storeTempFile()
{
return File::put($this->tempFileName, $this->photoData['Data']) > 0;
}
private function storeFileInfo()
{
$fileInfo = getimagesize($this->tempFileName);
// Could even be its own object
$this->fileInfo = [
'width' => $fileInfo[0],
'height' => $fileInfo[1],
'mimetype' => $fileInfo['mime'],
'extension' => $this->getFileExtension($fileInfo['mime'])
];
}
private function buildPhoto()
{
$this->photo->number = $this->photoData['Object-ID']; // Storing this because it is relevant order wise
$this->photo->width = $this->fileInfo['width'];
$this->photo->height = $this->fileInfo['height'];
$this->photo->path = $this->getFilePath();
}
private function getFilePath()
{
$path = [];
if ($this->listing->City == NULL)
{
$path[] = Str::slug('No City');
}
else
{
$path[] = Str::slug($this->listing->City, $separator = '-');
}
if ($this->listing->Development == NULL)
{
$path[] = Str::slug('No Development');
}
else
{
$path[] = Str::slug($this->listing->Development, $separator = '-');
}
if ($this->listing->Subdivision == NULL)
{
$pathp[] = Str::slug('No Subdivision');
}
else
{
$path[] = Str::slug($this->listing->Subdivision, $separator = '-');
}
if ($this->listing->MLSNumber == NULL)
{
$pathp[] = Str::slug('No MLSNumber');
}
else
{
$path[] = Str::slug($this->listing->MLSNumber, $separator = '-');
}
$path[] = $this->photoData['Object-ID'].'.'.$this->fileInfo['extension'];
return strtolower(join('/', $path));
}
private function pushToS3()
{
return $this->s3->putObject([
'Bucket' => $this->bucket,
'Key' => $this->photo->path,
'ContentType'=> $this->fileInfo['mimetype'],
'SourceFile' => $this->tempFileName
]);
}
private function getFileExtension($mime)
{
// Use better algorithm than this
$ext = str_replace('image/', '', $mime);
return $ext == 'jpeg' ? 'jpg' : $ext;
}
private function removeTempFile()
{
return File::delete($this->tempFileName);
}
}
Edit to show RetsPhoto
class RetsPhoto extends Eloquent {
protected $table = 'rets_property_photos';
public function listing() {
return $this->belongsTo('Listing', 'matrix_unique_id', 'matrix_unique_id');
}
}
Edit #2: Chunk Call
This is in the app/command and the only thing in there is the fire() function below:
public function fire()
{
// Turn off query logging
DB::connection()->disableQueryLog();
$feeds = RetsFeed::where('active','=',1)->get();
foreach ($feeds as $feed)
{
$class = "TempListing{$feed->board}";
$listings = $class::orderBy('MatrixModifiedDT','desc');
$listings->chunk(50, function($listings) use($feed) {
$listings->each(function($listing) use ($feed) {
ListingMigrator::migrateListing($listing,$feed);
echo "Feed: $feed->board\r\n";
echo "SubcondoName: $listing->SubCondoName\r\n";
echo "Development: $listing->Development\r\n";
echo "\r\n";
});
});
}
}
I think I have figured it out.
Your system holds in memory all of the photo data. As witnessed by the unset ($this->photoData);
The problem is that you need to first complete the process function. Your application is not likely processing ANY photos so when you keep grabbing them from the file system you run out of memory BEFORE you even process a single one.
To Confirm this, simply grab 1 file not using the chunk method.
I am not very familar with Laravel, it could be grabbing all of the files all at once as well and eating the ram.
You can do some tracing with memory_get_usage(true) to find out exactly where the ram is getting eaten from. I would suggest analysing the fire method first.