Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117747026
Item.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
8 KB
Referenced Files
None
Subscribers
None
Item.php
View Options
<?php
namespace
App\Fs
;
use
App\Backends\Storage
;
use
App\Traits\BelongsToUserTrait
;
use
App\Traits\UuidStrKeyTrait
;
use
Illuminate\Database\Eloquent\Casts\Attribute
;
use
Illuminate\Database\Eloquent\Model
;
use
Illuminate\Database\Eloquent\Relations\BelongsToMany
;
use
Illuminate\Database\Eloquent\Relations\HasMany
;
use
Illuminate\Database\Eloquent\SoftDeletes
;
/**
* The eloquent definition of a filesystem item.
*
* @property string $id Item identifier
* @property int $type Item type
* @property string $path Item path (readonly)
* @property int $user_id Item owner
*/
class
Item
extends
Model
{
use
BelongsToUserTrait
;
use
SoftDeletes
;
use
UuidStrKeyTrait
;
public
const
TYPE_FILE
=
1
;
public
const
TYPE_COLLECTION
=
2
;
public
const
TYPE_INCOMPLETE
=
4
;
public
const
TYPE_NOTEBOOK
=
8
;
/** @var list<string> The attributes that are mass assignable */
protected
$fillable
=
[
'user_id'
,
'type'
];
/** @var array<string, string> The attributes that should be cast */
protected
$casts
=
[
'created_at'
=>
'datetime:Y-m-d H:i:s'
,
'updated_at'
=>
'datetime:Y-m-d H:i:s'
,
];
/** @var string Database table name */
protected
$table
=
'fs_items'
;
/**
* Content chunks of this item (file).
*
* @return HasMany<Chunk, $this>
*/
public
function
chunks
()
{
return
$this
->
hasMany
(
Chunk
::
class
);
}
/**
* Copy the item to another location
*
* @param ?self $target Target folder
* @param ?string $name Optional name (for rename)
* @param int $depth Depth (-1 - infinity, 0 - only the collection)
*
* @return self Created copy item
*/
public
function
copy
(?
self
$target
,
?
string
$name
=
null
,
$depth
=
-
1
):
self
{
// Create the new item and copy its properties
$copy
=
new
self
();
$copy
->
type
=
$this
->
type
;
$copy
->
user_id
=
$this
->
user_id
;
$copy
->
updated_at
=
$this
->
updated_at
;
$copy
->
save
();
$props
=
$this
->
properties
()->
get
()->
mapWithKeys
(
function
(
$property
)
{
return
[
$property
->
key
=>
new
Property
([
'key'
=>
$property
->
key
,
'value'
=>
$property
->
value
])];
});
if
(
is_string
(
$name
)
&&
strlen
(
$name
))
{
$props
[
'name'
]->
value
=
$name
;
}
$copy
->
properties
()->
saveMany
(
$props
);
// Assign to the target folder
if
(
$target
)
{
$this
->
parents
()->
attach
(
$target
);
}
// FIXME: What can we do if copying content fails for any reason?
// Copy the file/folder contents
if
(
$this
->
isFile
())
{
Storage
::
fileCopy
(
$this
,
$copy
);
}
elseif
(
$depth
==
-
1
||
$depth
>
0
)
{
if
(
$depth
>
0
)
{
$depth
--;
}
$this
->
children
()->
get
()->
each
(
function
(
$item
)
use
(
$copy
,
$depth
)
{
$item
->
copy
(
$copy
,
null
,
$depth
);
});
}
return
$copy
;
}
/**
* Getter for the file path (without the filename) in the storage.
*/
protected
function
path
():
Attribute
{
return
Attribute
::
make
(
get
:
function
(
$value
)
{
if
(
empty
(
$this
->
id
))
{
throw
new
\Exception
(
"Cannot get path for an item without ID"
);
}
$id
=
substr
(
$this
->
id
,
0
,
6
);
return
implode
(
'/'
,
str_split
(
$id
,
2
));
}
);
}
/**
* Any (additional) properties of this item.
*
* @return HasMany<Property, $this>
*/
public
function
properties
()
{
return
$this
->
hasMany
(
Property
::
class
);
}
/**
* Obtain the value for an item property
*
* @param string $key Property name
* @param mixed $default Default value, to be used if not found
*
* @return string|null Property value
*/
public
function
getProperty
(
string
$key
,
$default
=
null
)
{
$attr
=
$this
->
properties
()->
where
(
'key'
,
$key
)->
first
();
return
$attr
?
$attr
->
value
:
$default
;
}
/**
* Obtain the values for many properties in one go (for better performance).
*
* @param array $keys Property names
*
* @return array Property key=value hash, includes also requested but non-existing properties
*/
public
function
getProperties
(
array
$keys
):
array
{
$props
=
array_fill_keys
(
$keys
,
null
);
$this
->
properties
()->
whereIn
(
'key'
,
$keys
)->
get
()
->
each
(
static
function
(
$prop
)
use
(&
$props
)
{
$props
[
$prop
->
key
]
=
$prop
->
value
;
});
return
$props
;
}
/**
* Check if the item is a collection (folder)
*/
public
function
isCollection
():
bool
{
return
(
bool
)
(
$this
->
type
&
self
::
TYPE_COLLECTION
);
}
/**
* Check if the item is a file
*/
public
function
isFile
():
bool
{
return
(
bool
)
(
$this
->
type
&
self
::
TYPE_FILE
);
}
/**
* Check if the item is incomplete
*/
public
function
isIncomplete
():
bool
{
return
(
bool
)
(
$this
->
type
&
self
::
TYPE_INCOMPLETE
);
}
/**
* Check if the item is a notebook collection
*/
public
function
isNotebook
():
bool
{
return
(
bool
)
(
$this
->
type
&
self
::
TYPE_NOTEBOOK
);
}
/**
* Move the item to another location
*
* @param ?self $target Target folder
* @param ?string $name Optional name (for rename)
*/
public
function
move
(?
self
$target
,
?
string
$name
=
null
):
void
{
if
(
$target
)
{
// move to another folder
$this
->
parents
()->
sync
([
$target
]);
}
else
{
// move to the root
$this
->
parents
()->
sync
([]);
}
if
(
is_string
(
$name
)
&&
strlen
(
$name
))
{
$this
->
setProperty
(
'name'
,
$name
);
}
}
/**
* Remove a property
*
* @param string $key Property name
*/
public
function
removeProperty
(
string
$key
):
void
{
$this
->
setProperty
(
$key
,
null
);
}
/**
* Create or update a property.
*
* @param string $key Property name
* @param string|null $value The new value for the property
*/
public
function
setProperty
(
string
$key
,
$value
):
void
{
$this
->
storeProperty
(
$key
,
$value
);
}
/**
* Create or update multiple properties in one fell swoop.
*
* @param array $data an associative array of key value pairs
*/
public
function
setProperties
(
array
$data
=
[]):
void
{
foreach
(
$data
as
$key
=>
$value
)
{
$this
->
storeProperty
(
$key
,
$value
);
}
}
/**
* Create or update a property.
*
* @param string $key Property name
* @param string|null $value The new value for the property
*/
private
function
storeProperty
(
string
$key
,
$value
):
void
{
if
(
$value
===
null
||
$value
===
''
)
{
$this
->
properties
()->
where
(
'key'
,
$key
)->
delete
();
}
else
{
// Note: updateOrCreate() uses two queries, but upsert() uses one
$this
->
properties
()->
upsert
(
// Note: Setting 'item_id' here should not be needed after we migrate to Laravel v11
[[
'key'
=>
$key
,
'value'
=>
$value
,
'item_id'
=>
$this
->
id
]],
[
'item_id'
,
'key'
],
[
'value'
]
);
}
}
/**
* All relations for this item
*
* @return HasMany<Relation, $this>
*/
public
function
relations
()
{
return
$this
->
hasMany
(
Relation
::
class
);
}
/**
* All locks for this item
*
* @return HasMany<Lock, $this>
*/
public
function
locks
()
{
return
$this
->
hasMany
(
Lock
::
class
);
}
/**
* Child relations for this item
*
* Used to retrieve all items in a collection.
*
* @return BelongsToMany<Item, $this>
*/
public
function
children
()
{
return
$this
->
belongsToMany
(
self
::
class
,
'fs_relations'
,
'item_id'
,
'related_id'
);
}
/**
* Parent relations for this item
*
* Used to retrieve all collections of an item.
*
* @return BelongsToMany<Item, $this>
*/
public
function
parents
()
{
return
$this
->
belongsToMany
(
self
::
class
,
'fs_relations'
,
'related_id'
,
'item_id'
);
}
/**
* Item type mutator
*
* @throws \Exception
*/
public
function
setTypeAttribute
(
$type
)
{
if
(!
is_numeric
(
$type
))
{
throw
new
\Exception
(
"Expecting an item type to be numeric"
);
}
$type
=
(
int
)
$type
;
if
(
$type
<
0
||
$type
>
255
)
{
throw
new
\Exception
(
"Expecting an item type between 0 and 255"
);
}
if
(
$type
&
self
::
TYPE_FILE
)
{
if
(
$type
&
self
::
TYPE_COLLECTION
||
$type
&
self
::
TYPE_NOTEBOOK
)
{
throw
new
\Exception
(
"An item type cannot be file and collection at the same time"
);
}
}
$this
->
attributes
[
'type'
]
=
$type
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Apr 4 2026, 12:03 AM (4 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18741264
Default Alt Text
Item.php (8 KB)
Attached To
Mode
rK kolab
Attached
Detach File
Event Timeline