Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

calin.ionut's avatar

create db and eloquent relations for a file manger app

I want to make a laravel 9 app where the auth user can create folders and files (on DB level ... not physical) and work similar like windows explorer (creating folders, files, navigating) ... but I am stuck on DB creation.

The files can be:

versioned - and only the default marked is visibile

shared - if the user want to share - to set custom permission to it (ex: can_view or can_version the file)

I was thinking like this the DB Structure:

Setting for files and folders folder_id = 0 => means that they are on the "root" level (but this could be tricky - because there is no folder with ID 0)

ex: if files or folders have folder_id = 1 means that they are under the folder with ID 1 the list (array of files) need to be sorted by name (folders first then files -like in file manager) - and with pagination.

Any idea will be great on how can I start creating the migrations....

For ex: How can I query the DB to get this array:

$files = array(
    ['id' => 1, 'type' => 'folder', 'name' => 'Folder 1', 'info' => ['date' => '20.02.2022', 'size' => 1.2]],
    ['id' => 2, 'type' => 'folder', 'name' => 'Test Folder 2', 'info' => ['date' => '21.02.2022', 'size' => 1.2]],
    ['id' => 1, 'type' => 'file', fileType => 'excel', 'name' => 'Excel file', 'info' => ['date' => '21.02.2022', 'size' => 1.1, 'members' => 0]],
    ['id' => 2, 'type' => 'file', fileType => 'pdf', 'name' => 'Sample PDF File', 'info' => ['date' => '19.01.2022', 'size' => 1.3, 'members' => 3]],
);

All the files and folders that are on root level (folder_id = 0) with all the info mentioned and paginated ?

*** UPDATE ***

I have created the relations:

For model User:

public function files() {
	return $this->hasMany(File::class);
}

public function folders() {
	return $this->hasMany(Folder::class);
}

public function sharedFiles() {
	return $this->belongsToMany(File::class, 'shared_files');
}

For File Model:

public function versions() {
	return $this->hasMany(Version::class);
}

public function logs() {
	return $this->hasMany(Log::class);
}

public function sharedUsers() {
	return $this->belongsToMany(User::class, 'shared_files');
}

For Folder Model:

public function files() {
	return $this->hasMany(Files::class);
}

public function parent() {
	return $this->belongsTo(Folder::class, 'parent_id')->where('parent_id', 0)->with('parent');
}

public function children() {
	return $this->hasMany(Folder::class, 'parent_id')->with('children');
}

For Log Model

public function file() {
	return $this->belongsTo(File::class);
}

For Version Model:

public function file() {
	return $this->belongsTo(File::class);
}
0 likes
4 replies
manojo123's avatar

Can you please elaborate your question? Do you have any specific question?

About the best relation to your tables I will define like this:

as I can see you will have shared files

  • users belongsToMany files
  • files belongsToMany users
  • file_user as pivot table

You will need many to many relationship in folders as well in order to the users with shared files be able to access the same file folder.

  • user belongsToMany folders
  • folders belongToMany users
  • folder_user as pivot table
  • folder belongsTo and HasMany folder
public function parent()
{
    return $this->belongsTo(Folder::class, 'folder_id')->where('folder_id',0)->with('parent');
}

public function children()
{
    return $this->hasMany(Folder::class, 'folder_id')->with('children');
}
  • file belongsTo Folder

  • folder hasMany files

  • file hasMany versions

  • version belongsTo file

calin.ionut's avatar

I think I found what I am looking for.

I am trying to use union to get:

  • one array with all folders and files (first folders - ordered by name, then second files - ordered by name) paginated.
$files = array(
  ['id' => 1, 'type' => 'folder', 'fileType => 'null', 'name' => 'Folder 1', 'date' => '20.02.2022', 'size' => 0, 'members' => 0],
  ['id' => 2, 'type' => 'folder', 'fileType => 'null', 'name' => 'Folder 2', 'date' => '20.02.2022', 'size' => 0, 'members' => 0],
  ['id' => 1, 'type' => 'file', 'fileType => 'pdf', 'name' => 'PDF File', 'date' => '20.02.2022', 'size' => 1.2, 'members' => 1],
  ['id' => 2, 'type' => 'file', 'fileType => 'word', 'name' => 'Word File', 'date' => '20.02.2022', 'size' => 1.3, 'members' => 5],
);
$folders = auth()->user()->folders()
->select(
	'id',
	'name',
	'created_at as date',
	DB::raw("'folder' as type"),
	DB::raw("'null' as fileType"),
	DB::raw("'0' as size"),
	DB::raw("'0' as members")
)
->where('parent_id', 0);
$files = auth()->user()->files()
->select(
	'id',
	'name',
	'created_at as date',
	DB::raw("'file' as type"),
	DB::raw("'null' as fileType"),
	DB::raw("'0' as size"),
	DB::raw("'0' as members")
)
->where('folder_id', 0);

$dataArray = $folders->union($files)->orderByRaw('type DESC, name ASC')->paginate(30)->toArray();

How to get (for files)

  • the fileType from file - where this field "type" is in "versions" table? Probably a left join...

  • date converted as Today (human readable)

  • count "members" (users) from shared_files table

?

calin.ionut's avatar

I have changed the files and now It works.....now only need to format the date: ex: Today (Carbon::parse(date)->diffForHumans()) - I am not sure that can be done this in the query....

$files = auth()->user()->files()
->leftJoin('versions', 'files.id', '=', 'versions.file_id')
->select(
	'files.id',
	'name',
	'files.created_at as date',
	DB::raw("'file' as type"),
	'versions.type as fileType',
	'versions.size'	
)
->withCount('sharedUsers as members')
->where('folder_id', 0);

Please or to participate in this conversation.