File
- Version
- 4.0 preview
- Updated
An uploaded file of any type: the file goes on disk under dirBase, the filename goes in the
column. The same machinery as image minus the image processing — no dimension checks,
no mutations.
Storage kind: column · Column: varchar(255)
Use it for assets that are stored and served as-is: a PDF datasheet, a CAD file, a connector's
certificate, a downloadable attached to an answer. Reach for image instead whenever
the file is a picture, even if you do not need mutations today — the dimension checks and the option
of adding mutations later come free, and switching type afterwards means re-uploading.
Settings
| Setting | Meaning |
|---|---|
dirBase | Required. Filesystem directory written to. Created (recursively, 0777) if missing |
urlBase | URL base served from. Without it, reads expose no _href |
filename | Fixed base filename instead of the uploaded one |
appendSerial | Append a random 4-digit serial to the base name — a cache-buster |
allowedExtensions | Array of permitted extensions, lower-case, without the dot |
allowedMimeTypes | Array of permitted MIME types — checked as well as the extension |
maxFileSizeKb | Upload ceiling in KB — this is what size meant on a file property |
options | FILENAME_TO_RECORD_ID, NODELETEFILE, NO_SAVE_FILENAME |
The filename is persisted by default
As with image, store() calls updateFilenameBaseTable() unless the definition opts
out with NO_SAVE_FILENAME.
This used to be opt-in, behind a SAVE_FILENAME tag. Omitting it uploaded the file and never touched
the column, and because prepareForStorage() has already put the previous filename into the data
object, the record simply kept pointing at the old file — no error, nothing in a log. Every shipped
file definition set the tag, so it was never really optional.
FILENAME_TO_RECORD_ID names the stored file after the record id; NODELETEFILE suppresses the
"delete file at save" checkbox. The checkbox posts <propertyName>-delete=1, and it only renders
when a file is stored, NODELETEFILE is absent, the property is not required, and the record id
is not 0. A delete flag arriving when the property is not deletable makes store() throw.
Validation
check() refuses on the first problem it finds, unlike image, which collects them all:
| Checked | Condition |
|---|---|
| Presence | Only when required, the field applies, and the record is new (empty($data->id)) |
maxFileSizeKb | filesize() of the temp file against the ceiling |
allowedMimeTypes | KenedoFileHelper::getMimeType(). Skipped silently if the system cannot determine one |
allowedExtensions | The uploaded name's extension |
Declare both allowedExtensions and allowedMimeTypes. An extension is a claim by the client; the
MIME check looks at what was actually sent — but it is also the check that can silently not run, so
neither alone is enough.
Note that the required-file check only fires on an insert. On an update, an existing record with a missing file is not re-flagged.
How the filename is built
Same order as image: FILENAME_TO_RECORD_ID → the definition's filename → the uploaded name,
lower-cased and stripped of its extension. Then appendSerial appends - plus a random 4-digit
number, and the uploaded extension is put back.
On a copy there is one difference from image: without appendSerial, file avoids a
collision by probing -1, -2, … until the name is free on disk. image has no such loop, so an
image copy without appendSerial can overwrite — though not in the shipped configuration, where
every image property sets either appendSerial or FILENAME_TO_RECORD_ID, and the new record's id
cannot collide.
What reads produce
| Key | Holds |
|---|---|
<name> | the filename |
<name>_href | urlBase + / + filename, when urlBase is set |
<name>_path | dirBase + / + filename, when dirBase is set |
Unlike image, these keys are added whenever the bases are configured — they are set to '' for a
record with no file rather than being left off.
size meant two different things
On a file property size was a kilobyte ceiling; on a text property it was an input's maxlength.
One key, two unrelated meanings, disambiguated only by the type. They are now maxFileSizeKb and
maxLength, with a shim in modernizeOldPropertySettings() routing an old size by type.
Notes
- Deleting a record does delete the file.
KenedoPropertyFile::delete()unlinks it before the row goes, and a failure to unlink is logged rather than raised — the record still goes. You do not need anafterDelete()for this. - The upload is
rename()d out of the temp directory, not copied the wayimagedoes it, then chmod'ed0775. On hosts where the temp dir is on a different filesystem that is the faster path. - Replacing a file unlinks the previous one, but only when the new name differs. With a fixed
filenameand noappendSerialthe name is the same and the file is simply overwritten. - Copying a record whose source file is missing logs a warning and continues with an empty value —
it still writes the row, because a
storeExternallyfile property may be the only column in its foreign table and a row has to exist.imagethrows in the same situation. storeExternallymoves the filename column to another table; the property implements the branch itself. The files always live underdirBase.
@see image.md
@see ../com_configbox_property_types.md §3 for storeExternally