Laravel delete all rows related to one another in the same table - laravel

Here i have folders table that contains folder information like name etc. all folder may have some sub folders. when i want to remove the parent folder i need to delete all the sub folders and all sub sub folders under sub folders.
for example in the picture if i delete folder id 1, it must delete folder id 4, 5, 6, 7, 8, 9 and 10. because all the folders are inside folder id 1.
i think i made you understand.
Folder::where('id', $id)->delete();
This delete only to folder with the given id, not the sub folders
Thanks all

You can define deleting in the Folder model. I suppose that you also defined the relation
public function subfolders() {
return $this->hasMany(Folder::class, 'parent_id');
}
So you should add this to your Folder model:
public static function boot () {
parent::boot();
self::deleting(function ($folder) {
foreach ($folder->subfolders as $subfolder) {
$subfolder->delete();
}
});
}
This will be triggered on delete action and will delete all the subfolders, deleting of each of them will also run this function etc.

easy way you can delete first relation and after that del folder
Folder::where('paren_id', $id)->delete();
Folder::where('id', $id)->delete();

Related

Using Storage::makeDirectory() not creating a folder in laravel

I'm trying to save a folder to the storage folder, but it isn't creating the folder.
What happens is that, I save the folder name in a form and what I want to happen is that if that folder doesn't exist then create it.
Here is my code
public function createFolder()
{
$base = storage_path("app/folder/".request('folder'));
if(!file_exists($base))
{
Storage::makeDirectory($base);
}
}
You can do some think like this
$path="folder/".request()->folder;
$folderExist= Storage::exists($path);
if(!$folderExist){
Storage::makeDirectory($path);
}

Dynamic routes with Laravel 8

I have a problem with routes in Laravel. I am working on DMS (Document Management System), I need to make folders and infinite sub-folders.
This leeds me to block the way to make hundreds or thousands of routes to achieve the goal.
I need to make fully dynamic routes as the following example:
('/folders',[FolderController::class , 'index']) //to retrieve all folders
('/folders/{x}' , [FolderController::class , 'show']) // to retrieve level one sub-folder
('/folders/{x}/{y}' ,[FolderController::class , 'xyz']) // to retrieve level two sub-folder
This leeds me to make infinite routes for each sub-folders level.
How to make dynamic routes for dynamic sub-folders level?
Thanks in advance.
You can use a wildcard parameter:
Route::get('/folders/{x}' , [FolderController::class , 'show'])
->where('x', '.*');
then your controller route would be:
public function show($x = '') {
$path = explode('/', $x);
// $path is an array with the directory structure
// Do whatever you want with it e.g.
if (empty($path)) {
return $this->index();
}
}
Don't do this you will end up with a lot a route and performance issues. Instead do only one route with an optional parameters as the parent folder.
'/folders/{x?}' , [FolderController::class , 'show']);
In your db every folder should have an id and a parent id.
when the parent id is null this mean it's a root folder.
Then you can recursively get all the child/parent folder

How to make:folder in folder in folder... to the infinity in Laravel

I need to make the option that in folder you can create new folder,then a new folder inside the new folder... and so on indefinitely. Like we can do it on a desktop.
I can't find anything similar in the documentation.
I'm wondering if I can have a relation in Folder Model:
public function folder()
{
return $this->belongsTo(Folder::class);
}
public function folders()
{
return $this->hasMany(Folder::class);
}
and does this work at all?
I'm also wondering, what would a table for folders in a database look like?
Can we have:
$table->unsignedBigInteger('folder_id');
$table->foreign('folder_id')
->references('id')
->on('folder')
->onDelete('cascade');
Also, I have to do everything on the API route, so I'm wondering, how I can add /folder/{folder} every time I create new folder?
The way you are showing is defining a 1 to many relationship between a folder. This should be enough, since a folder may only have 1 parent folder. I would recommend the following relationship naming:
public function parentFolder()
{
return $this->belongsTo(Folder::class);
}
public function childFolders()
{
return $this->hasMany(Folder::class);
}
The route will be a bit more tricky though:
Route::get('/folder/{folder}', function ($folder) {
$hierarchy = explode('/', $folder);
$root = array_shift($hierarchy);
$currentFolder = Folder::where('name', $root)->doesntHave('parentFolder')->firstOrFail(); // Root folder has no parents
while (!empty($hierarchy)) {
$currentFolder = Folder::where('name', array_shift($hierarchy))
->whereHas('parentFolder', function ($q) use ($currentFolder) {
$q->where('id', $currentFolder->id);
})->firstOrFail();
}
// $currentFolder should be the correct folder
})->where([ 'folder' => '.*' ]); // {folder} can be any string
If you want to simulate a Linux like system you can always modify the above to add a folder named / as the root of all folders. This will require you to get this folder first before looping through to get the directory structure

How can I limit/restrict users who can access files in my storage's folder? (laravel)

I already created a symbolic link to access the public folder from storage storage/app/public
php artisan storage:link
This time I'm having questions on my mind on how to filter users who can view the image? Like, How can I implement Only Me, My Friends Only?
Any ideas Sirs?
NOTE: There is a little performance issue with this solution. This is just to answer the question, scroll down more to see other approach from other.
<input type="file" name="file">
I personally save the files inside /storage/app/files not inside the /public folder (As it tells public for everyone).
request()->file->storeAs('files', 'filename.ext');
To view & add restrictions: create a route responsible for viewing:
Route::get('files/{$filename}', 'FileController#show')->name('files.show);
Controller:
public function show($filename)
{
$path = storage_path('app/files/'.$filename);
//do some If-Else or Filters here, for user who can access the file
return response()->download($path, null, [], null);
}
To delete the file:
File::delete('app/files/'.$filename);
i think you should set a field 'image_option' in your table 'storage_file'.
image_option: string,
image_option = {privacy_level:[1, 2, 3]}
privacy_level = 1 // public
privacy_level = 2 // only me
privacy_level = 3 // only friend only

Checking folder already existed and if not create a new folder by id in laravel

i want to store my image to a specific folder and the folder will named by page id. For example if Page id=1, the folder location should be public/pages/page_id/image_here.
If the folder are not existed yet the system will generate and named with their page id.
$id=1;
$directoryPath=public_path('pages/' . $id);
if(File::isDirectory($directoryPath)){
//Perform storing
} else {
Storage::makeDirectory($directoryPath);
//Perform storing
}
But i having error that "mkdir(): Invalid argument".
Can i know why it happen?
And after my research some people say the folder name should based with id+token so intruder cannot search image based on id, is there possible to achieve?
I had the same problem, but when I use File instead of Storage it works!
$id=1;
$directoryPath=public_path('pages/'.$id);
//check if the directory exists
if(!File::isDirectory($directoryPath)){
//make the directory because it doesn't exists
File::makeDirectory($directoryPath);
}
//Perform store of the file
Hope this works!
When you use Storage facade, it uses local disk as default which is configured to work with storage_path().
So, if you want to create directory in public directory, use File::makeDirectory which is just simple wrapper for mkdir() with additional options or use mkdir() directly:
File::makeDirectory($directoryPath);
mkdir($directoryPath);
For basic Laravel file system the syntax is :
At very top under namespace write:
use File;
Then in your method use:
$id=1;
$directoryPath=public_path('pages/' . $id);
if(File::isDirectory($directoryPath)){
//Perform storing
} else {
File::makeDirectory($directoryPath, 0777, true, true);
//Perform storing
}

Resources