<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Arr;
/**
* @property string $id
* @property string $path
* @property Collection<array-key, Song> $songs
* @property ?Folder $parent
* @property Collection<array-key, Folder> $subfolders
* @property-read string $name
* @property-read bool $is_uploads_folder Where the folder is the uploads folder by any user
* @property-read ?int $uploader_id
* @property ?string $parent_id
* @property string $hash
*/
class Folder extends Model
{
use HasFactory;
use HasUuids;
protected $guarded = [];
public $timestamps = false;
protected $appends = ['name'];
public function songs(): HasMany
{
return $this->hasMany(Song::class)->orderBy('path');
}
public function parent(): BelongsTo
{
return $this->belongsTo(__CLASS__);
}
public function subfolders(): HasMany
{
return $this->hasMany(__CLASS__, 'parent_id')->orderBy('path');
}
public function browsableBy(User $user): bool
{
return !$this->is_uploads_folder || $this->uploader_id === $user->id;
}
protected function name(): Attribute
{
return Attribute::get(fn () => Arr::last(explode(DIRECTORY_SEPARATOR, $this->path)));
}
protected function isUploadsFolder(): Attribute
{
// An uploads folder has a format of __KOEL_UPLOADS_$<id>__ and is a child of the root folder
// (i.e., it has no parent).
return Attribute::get(
fn () => !$this->parent_id && preg_match('/^__KOEL_UPLOADS_\$\d+__$/', $this->name) === 1
);
}
protected function uploaderId(): Attribute
{
return Attribute::get(function () {
if (!$this->is_uploads_folder) {
return null;
}
$matches = [];
preg_match('/^__KOEL_UPLOADS_\$(\d+)__$/', $this->name, $matches);
return (int) Arr::get($matches, 1);
})->shouldCache();
}
}