Index

FileController

MMO\edms\controllers · 1 symbol · generated 5 Oct 2026

class

FileController

FileController.php:44

The files over http, for the logged-in user (FileManager does the work, and checks the rights).

class MMO\edms\controllers\FileController extends MMO\core\classes\aController
Namespace
MMO\edms\controllers
Extends
aController
The api (`edms/...`): | route | | |---|---| | `GET edms/files.json` | the files the user can see: `labels`, `recursive`, `attachment`, `q`, `mine`, `trash`, `sort`, `offset`, `limit` | | `GET edms/files/{id}.json`, `PATCH` it, `DELETE` it | a file: `PATCH` its `label`, `description`, `data`, `labels`/`addLabels`/`removeLabels`; `DELETE` puts it in the trash (`permanent=1`: deletes it from the trash) | | `POST edms/files/{id}/restore.json` | takes it out of the trash | | `GET edms/files/{id}/content` | its bytes (`inline=1` to show it; `Range` and `If-None-Match` answered) | | `POST edms/files/bulk.json` | `{action: trash|restore|delete|label|unlabel, ids, labels}` for several files | | `GET edms/files/archive.zip?ids=` | several files, in a zip | | `GET edms/labels.json`, `POST` one, `PATCH`/`DELETE edms/labels/{id}.json` | the labels | | `POST edms/uploads.json`, `PUT edms/uploads/{id}`, `GET`/`DELETE edms/uploads/{id}.json` | an upload, in chunks | A request changing something sends the session's CSRF token in the `X-CSRF-Token` header ([`Token`](https://mcp.mmoframework.fr/documentation/mmo.edms/php/controllers/FileController.md#filecontroller-token), given to the pages in `MMO.edms.config.token`, and by `GET edms/token.json`), unless it is authenticated by an `Authorization` header. The routes of edms 2 stay: `files/list.{json,csv}`, `files/mylist.{json,csv}`, `files/labels.json`, `files/schemas.json` and `download/{id}`.

Index

CSRF_KEY
LIST_FIELDSthe fields a listing gives of a file (exportFile), for the schema it links to
privateKey
publicKey
attachments($route)
BaseUrl() static
body($route)
checkToken($route)Make sure a request changing something comes from a page of the site: it has the session's token, or is authenticated by an Authorization header (which a browser does not send on its own)
ContentDisposition($name, $inline) static
document($route)
exportFile($file, $user)A file as the routes give it to $user: what the page needs, nothing about the server (where the bytes are) nor about the owner (their title only), nor about the labels $user may not know -- a priva…
file($route)
flag($route, $name)
Header($request, $name) static
label($route)
labels($route, $user)
onRoute($route)
routeAbortUpload($route)
routeArchive($route)
routeBulk($route)Act on several files: {action, ids, labels} -- trash, restore, delete (from the trash), label or unlabel (labels: label ids).
routeContent($route)
routeCreateLabel($route)Make a label: {label, parent, description, color, properties} -- without a parent, a tag of the user
routeDeleteFile($route)
routeDeleteLabel($route)
routeDownload($route)
routeFile($route)
routeFiles($route)The files the user can see
routeLabels($route)The tags of the current user, and the global ones: a tree of {value, label, title, color, path, children}
routeLabelTree($route)
routeList($route)
routeMyList($route)
routeRestoreFile($route)
routeSchemas($route)Get the schema associated to a list of labels
routeStartUpload($route)Start an upload: {name, size, labels, attachment, temporary} (labels: label ids, or quoted paths and "#tags", the user's own tags made if missing).
routeToken($route)The session's CSRF token (Token): a page holds the one of the session it was made in, which the server no longer has once the session changed (a new login, a page the browser restored), and `M…
routeUpdateFile($route)
routeUpdateLabel($route)
routeUpload($route)
routeUploadChunk($route)Send a chunk of the upload {id}: the body is its bytes, the header Content-Range: bytes {first}-{last}/{size} (or the query's offset) says where they go.
SchemaUrl($fields, $labels) static
sendFile($route, $inline)
TemporaryFile($id, $user) staticThe file a temporary upload (temporary) of $user brought: the page sends its id back to the application, which takes the file -- to move or to delete, it is the caller's.
Token() static
UploadUrl() static
user($route)

Constants2

CSRF_KEY

const CSRF_KEY = 'MMO\\edms\\controllers\\FileController'

LIST_FIELDS

the fields a listing gives of a file (exportFile), for the schema it links to

const LIST_FIELDS = ['label', 'size', 'url', 'description', 'ctime', 'labels', 'id', 'data']

Properties2

privateKey

?MMO\oauth\interfaces\iPrivateKey $privateKey = null
Type
null | iPrivateKey

publicKey

?MMO\oauth\interfaces\iPublicKey $publicKey = null
Type
null | iPublicKey

Methods41

attachments($route)

FileController.php:193
protected function attachments(MMO\core\server\Route $route): ?array
$routeRoute
returnsnull | arraythe entities the files must be attached to (attachments: uids, comma separated), null when the request asks for none -- an empty list when none of them exists

body($route)

FileController.php:153
protected function body(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the body of the request, a json object

checkToken($route)

FileController.php:135

Make sure a request changing something comes from a page of the site: it has the session's token, or is authenticated by an Authorization header (which a browser does not send on its own)

protected function checkToken(MMO\core\server\Route $route): void
$routeRoute
returnsvoid
throws(403) if it has not

exportFile($file, $user)

FileController.php:210

A file as the routes give it to $user: what the page needs, nothing about the server (where the bytes are) nor about the owner (their title only), nor about the labels $user may not know -- a private tag of the owner, and the custom fields it defines. The custom fields (data) are columns too, but never replace one of the file's own.

function exportFile(MMO\edms\entities\File $file, MMO\oauth\interfaces\iClient $user): array
$fileFile
$useriClient
returnsarraymixed>

file($route)

FileController.php:160
protected function file(MMO\core\server\Route $route): MMO\edms\entities\File
$routeRoute
returnsFilethe file {id} @throws e404 if there is none

flag($route, $name)

FileController.php:200
protected function flag(MMO\core\server\Route $route, string $name): bool
$routeRoute
$namestring
returnsboolthe boolean $name of the query (1, true...)

label($route)

FileController.php:167
protected function label(MMO\core\server\Route $route): MMO\edms\entities\Label
$routeRoute
returnsLabelthe label {id} @throws e404 if there is none

labels($route, $user)

FileController.php:178
protected function labels(MMO\core\server\Route $route, MMO\oauth\interfaces\iClient $user): array
$routeRoute
$useriClient
returnsarraythe labels the request asks for (labels: ids, or quoted paths and "#tags")
throwsif one of them does not exist, or is one $user may not know: the same answer, so that nobody learns what labels others have

routeAbortUpload($route)

FileController.php:585
#[MMO\core\attributes\APIRoute('DELETE|edms/uploads/{id}.json', 'Stop an upload: what it received is deleted', mediaTypes: ['json'])] function routeAbortUpload(MMO\core\server\Route $route): array
$routeRoute
returnsarraystring, deleted: bool}

routeArchive($route)

FileController.php:372
#[MMO\core\attributes\APIRoute('GET|edms/files/archive.zip?ids={ids}', 'Several files, in a zip')] function routeArchive(MMO\core\server\Route $route): MMO\edms\server\FileResponse
$routeRoute
returnsFileResponsethe files ids (comma separated) the user can see, in a zip

routeBulk($route)

FileController.php:341

Act on several files: {action, ids, labels} -- trash, restore, delete (from the trash), label or unlabel (labels: label ids). A file the user cannot act on is reported, the others are done.

#[MMO\core\attributes\APIRoute('POST|edms/files/bulk.json', 'Act on several files: trash, restore, delete, label, unlabel', mediaTypes: ['json'])] function routeBulk(MMO\core\server\Route $route): array
$routeRoute
returnsarraylist<mixed>, errors: array<string, string>}

routeContent($route)

FileController.php:331
#[MMO\core\attributes\APIRoute('GET|edms/files/{id}/content?inline={?inline}', 'The bytes of a file: `inline=1` to show it rather than save it')] function routeContent(MMO\core\server\Route $route): MMO\edms\server\FileResponse
$routeRoute
returnsFileResponsethe bytes of the file {id}

routeCreateLabel($route)

FileController.php:450

Make a label: {label, parent, description, color, properties} -- without a parent, a tag of the user

#[MMO\core\attributes\APIRoute('POST|edms/labels.json', 'Make a label (without a `parent`, a tag of the user)', mediaTypes: ['json'])] function routeCreateLabel(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed>

routeDeleteFile($route)

FileController.php:308
#[MMO\core\attributes\APIRoute('DELETE|edms/files/{id}.json?permanent={?permanent}', 'Put a file in the trash, or (`permanent=1`) delete it from the trash', mediaTypes: ['json'])] function routeDeleteFile(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the file {id}, in the trash -- or {id, deleted: true} once deleted for good

routeDeleteLabel($route)

FileController.php:475
#[MMO\core\attributes\APIRoute('DELETE|edms/labels/{id}.json', 'Delete a label: its files stay, without it', mediaTypes: ['json'])] function routeDeleteLabel(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed, deleted: bool}

routeDownload($route)

FileController.php:723
#[MMO\core\attributes\APIRoute('GET|download/{id}')] function routeDownload(MMO\core\server\Route $route): MMO\edms\server\FileResponse
$routeRoute
returnsFileResponsethe file's content (edms 2's url of routeContent)

routeFile($route)

FileController.php:290
#[MMO\core\attributes\APIRoute('GET|edms/files/{id}.json', 'A file', mediaTypes: ['json'])] function routeFile(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the file {id}

routeFiles($route)

FileController.php:262

The files the user can see

#[MMO\core\attributes\APIRoute('GET|edms/files.json?labels={?labels}&recursive={?recursive}&attachment={?attachment}&q={?q}&mine={?mine}&trash={?trash}&sort={?sort}&offset={?offset}&limit={?limit}', […2 items], mediaTypes: ['json'])] function routeFiles(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed>> exportFile

routeLabels($route)

FileController.php:696

The tags of the current user, and the global ones: a tree of {value, label, title, color, path, children}

#[MMO\core\attributes\APIRoute('GET|files/labels.json', [])] function routeLabels(MMO\core\server\Route $route)
$routeRoute
returnsmixed>>

routeLabelTree($route)

FileController.php:441
#[MMO\core\attributes\APIRoute('GET|edms/labels.json', 'The labels the user can see, as a tree', mediaTypes: ['json'])] function routeLabelTree(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed>> the labels the user can see, as a tree (FileManager::getLabelTree)

routeList($route)

FileController.php:673
#[MMO\core\attributes\APIRoute('GET|files/list.{extension}?labels={?labels}&recursive={?recursive:boolean}&attachments={?attachments}', […2 items], mediaTypes: ['json', 'csv'])] function routeList(MMO\core\server\Route $route)
$routeRoute
returnsmixed>> the files matching the query the current user can see (exportFile)

routeMyList($route)

FileController.php:649
#[MMO\core\attributes\APIRoute('GET|files/mylist.{extension}?labels={?labels}&attachments={?attachments}', […2 items], mediaTypes: ['json', 'csv'])] function routeMyList(MMO\core\server\Route $route)
$routeRoute
returnsmixed>> the current user's files matching the query (exportFile)

routeRestoreFile($route)

FileController.php:323
#[MMO\core\attributes\APIRoute('POST|edms/files/{id}/restore.json', 'Take a file out of the trash', mediaTypes: ['json'])] function routeRestoreFile(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the file {id}, out of the trash

routeSchemas($route)

FileController.php:622

Get the schema associated to a list of labels

#[MMO\core\attributes\APIRoute('GET|files/schemas.json?labels={?labels}&fields={?fields}', […2 items], mediaTypes: ['json'])] function routeSchemas(MMO\core\server\Route $route): array
$routeRoute
returnsarray
throws

routeStartUpload($route)

FileController.php:506

Start an upload: {name, size, labels, attachment, temporary} (labels: label ids, or quoted paths and "#tags", the user's own tags made if missing). The answer's id names it for the next requests.

#[MMO\core\attributes\APIRoute('POST|edms/uploads.json', 'Start an upload', mediaTypes: ['json'])] function routeStartUpload(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> Upload::jsonSerialize, with the size of a chunk (chunkSize)

routeToken($route)

FileController.php:492

The session's CSRF token (Token): a page holds the one of the session it was made in, which the server no longer has once the session changed (a new login, a page the browser restored), and MMO.edms.Api asks for it again when a request is refused for it. A GET is no risk: another site cannot read the answer (no CORS)

#[MMO\core\attributes\APIRoute('GET|edms/token.json', 'The session\'s CSRF token, for the requests changing something', mediaTypes: ['json'])] function routeToken(MMO\core\server\Route $route): array
$routeRoute
returnsarraystring}

routeUpdateFile($route)

FileController.php:299
#[MMO\core\attributes\APIRoute('PATCH|edms/files/{id}.json', 'Change a file: its `label`, `description`, `data`, or `labels`/`addLabels`/`removeLabels` (label ids)', mediaTypes: ['json'])] function routeUpdateFile(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the file {id}, changed

routeUpdateLabel($route)

FileController.php:466
#[MMO\core\attributes\APIRoute('PATCH|edms/labels/{id}.json', 'Change a label: its `label`, `description`, `color`, `properties`', mediaTypes: ['json'])] function routeUpdateLabel(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the label {id}, changed: its label, description, color, properties

routeUpload($route)

FileController.php:543
#[MMO\core\attributes\APIRoute('GET|edms/uploads/{id}.json', 'An upload: how much it received', mediaTypes: ['json'])] function routeUpload(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed> the upload {id}: how much it received (offset), to resume it

routeUploadChunk($route)

FileController.php:559

Send a chunk of the upload {id}: the body is its bytes, the header Content-Range: bytes {first}-{last}/{size} (or the query's offset) says where they go. The last chunk makes the file (file in the answer), unless the upload is temporary.

#[MMO\core\attributes\APIRoute('PUT|edms/uploads/{id}?offset={?offset}', 'Send a chunk of an upload', mediaTypes: ['json'])] function routeUploadChunk(MMO\core\server\Route $route): array
$routeRoute
returnsarraymixed>

sendFile($route, $inline)

FileController.php:424
protected function sendFile(MMO\core\server\Route $route, bool $inline): MMO\edms\server\FileResponse
$routeRoute
$inlinebool
returnsFileResponsethe file {id}, if the user can see it

TemporaryFile($id, $user)

staticFileController.php:600

The file a temporary upload (temporary) of $user brought: the page sends its id back to the application, which takes the file -- to move or to delete, it is the caller's.

static function TemporaryFile(string $id, MMO\oauth\interfaces\iClient $user): ?string
$idstring
$useriClient
returnsnull | stringthe local file, null if $user has no such complete temporary upload
$filename = FileController::TemporaryFile($route->get('image'), \MMO\oauth\user());

Token()

staticFileController.php:53
static function Token(): string
returnsstringthe CSRF token of the session, for the requests changing something

user($route)

FileController.php:124
protected function user(MMO\core\server\Route $route): MMO\oauth\interfaces\iClient
$routeRoute
returnsiClientthe logged-in user
throws(401) if nobody is
Inherited members (55)
ConstantsDeclared byDescription
ALERTiLogLevelAlert: Action must be taken immediately.
ALLiLogLevelMask for all
ALL_PLUSiLogLeveldebug everything
BACKTRACEiLogLevel
CRITICALiLogLevelCritical: Critical conditions.
DEBUGiLogLevelDebug: Detailed debug information.
DEEPiLogLeveldebug everything with arguments
EMERGENCYiLogLevelEmergency: System is unusable.
ERRORiLogLevelError: Runtime errors that do not require immediate action but should typically be logged and monitored.
ERROR_PLUSiLogLevelMask for all error
FATALiLogLevelMask for all fatal error
INFOiLogLevelInfo: Interesting events.
INFO_PLUSiLogLevelMask for all errors/warning/notices/info
MEMORYiLogLevelinclude backtrace object
NOTICEiLogLevelNotice: Normal but significant events.
NOTICE_PLUSiLogLevelMask for all errors/warning/notices/info
TRACEiLogLevelinclude backtrace as origins
WARNINGiLogLevelWarning: Exceptional occurrences that are not errors.
WARNING_PLUSiLogLevelMask for all errors and warnings
PropertiesDeclared byDescription
verbosityaModule
MethodsDeclared byDescription
alert($message, $context)aModuleAction must be taken immediately.
backtraces($message, $context)aModuleForce-log a message at INFO level together with a full stack trace/memory snapshot (iLogLevel::BACKTRACE), bypassing the verbosity mask entirely (any non-zero verbosity is enough to trigger it).
Configure($config)aModuleMerge $config into this module's configuration in the shared Configuration.
critical($message, $context)aModuleCritical conditions. No-op if CRITICAL is currently filtered out by the verbosity mask.
debug($message, $context)aModuleDetailed debug information.
debugName()aModuleHuman-readable identifier used as the default {origin} in this instance's log messages.
DefaultConfig()aModuleThe config a module starts from before anything loaded via Configuration is merged in.
emergency($message, $context)aModuleSystem is unusable. No-op if EMERGENCY is currently filtered out by the verbosity mask.
error($message, $context)aModuleRuntime errors that do not require immediate action but should typically be logged and monitored.
ExtractRoutes($config)aControllerExtract all the APIRoute from this class, regardless of the fact they are registered in the application
getVerbosity()aModule
HasRoutes()aControllerTells if any APIRoute are registered in the application
info($message, $context)aModuleInteresting events. No-op if INFO is currently filtered out by the verbosity mask.
Instantiate($config)aModule(Re)create the shared instance immediately, configured with $config merged into the class's existing config.
IsShared()aModule
Link($method, $data)aControllerBuild a Link (URL + label/icon/description/title, taken from the route's APIRoute metadata) for a registered route.
log($level, $message, $context)aModuleLogs with an arbitrary level.
notice($message, $context)aModuleNormal but significant events.
offsetExists($key)aModule\ArrayAccess::offsetExists -- tells whether $key is a declared property at all, regardless of whether it is currently readable/writable through array access.
offsetGet($key)aModule\ArrayAccess::offsetGet -- reads a property directly, unless it has a #[Serialize(serialize: 'methodName')] attribute, in which case that zero-argument method is called instead (e.g.
offsetSet($key, $value)aModule\ArrayAccess::offsetSet -- sets a property directly, unless it has a #[Serialize(unserialize: 'methodName')] attribute, in which case that method is called with $value instead (e.g.
offsetUnset($key)aModule\ArrayAccess::offsetUnset -- equivalent to $module[$key] = null.
Route($method)aControllerGet a registered APIRoute WARNING: if this class was not registered in the application, it will return null.
Routes()aControllerGet a list of registered APIRoutes (from this class) in the application WARNING: if this class was not registered in the application, it will return an empty array.
serialize($path, $serializer)aModule\MMO\core\interfaces\iSerializable::serialize -- exports every property (via
setVerbosity($verb)aModuleSet the current verbosity mask, replacing whatever it was before.
Shared()aModuleGet the shared instance, creating (and configuring) it on first call.
testVerbosity($level)aModuleTest whether a given level (or set of levels) is currently enabled by this instance's verbosity mask.
traitUnshare($serialize)aModuleRemove the shared instance, so the next Shared() call creates a fresh one.
unserialize($data, $path, $instances)aModule\MMO\core\interfaces\iSerializable::unserialize -- merges $data onto DefaultConfig, runs it through the (possibly overridden) constructor, then applies each resulting value to its property (via
Unshare($serialize)aModuleLike tSingleton::Unshare, but also disconnects this module's instance from every event it was listening to (via Event::DisconnectListeners) before dropping it.
Url($method, $data)aControllerBuild the URL for a registered route, filling in any {placeholder} from $data.
warning($message, $context)aModuleExceptional occurrences that are not errors.
__construct($config)aModuleprotected constructor, so it is not possible to do new Module(...) called by the serialization process just before being injected with data.
__wakeup()aControllerCalled automatically right after the controller's shared instance is built (aModule::unserialize): registers onRoute as a Route listener with a low priority (-10), so it…