Summary
Competitions currently take an optional banner_image_url for the banner image. Provide a proper image upload as an alternative, using the core file module. The URL field stays as a fallback; an uploaded image wins when both are set.
Implementation sketch
-
Migration — add banner_file_guid (varchar 36, nullable) to kickoff_competition. The upload becomes a core File record attached to the competition; the GUID column marks which attached file is the banner. (Core's File::$category is still marked experimental, so a dedicated column is preferred.)
-
Model (Competition)
- Virtual
$bannerUpload attribute (yii\web\UploadedFile) with an image validation rule (extensions png/jpg/jpeg/webp, max size, optionally min dimensions).
getBannerImageUrl(): ?string — uploaded file's File::getUrl() if set, else banner_image_url, else null.
-
Form (views/admin/_form.php) — enctype: multipart/form-data, fileInput() field, thumbnail preview of the current banner, "remove banner" checkbox.
-
Controller (AdminController::actionCreate/actionUpdate) — UploadedFile::getInstance() before save; on success create a core FileUpload (setUploadedFile() → save()), attach to the competition, store the GUID; delete the previously attached file on replace/remove.
-
Access control — File::canView() delegates to the underlying record when it implements humhub\interfaces\ViewableInterface. Competition::canView() already exists (v1.0.2 access gating); declare the interface and widen the signature to canView($user = null). Restricted competitions' banners are then gated exactly like their pages. Without this, files attached to plain records are world-readable and would leak banners of restricted competitions.
-
View (views/competition/_banner.php) — use $competition->getBannerImageUrl() instead of reading banner_image_url directly.
Notes
- Core does not auto-delete attached files of plain ActiveRecords — add
Competition::afterDelete() to remove the banner file.
- Plain multipart form post; core's ajax
UploadButton widget is not needed.
- Fully backwards compatible (
banner_image_url untouched) — no minVersion bump.
Summary
Competitions currently take an optional
banner_image_urlfor the banner image. Provide a proper image upload as an alternative, using the corefilemodule. The URL field stays as a fallback; an uploaded image wins when both are set.Implementation sketch
Migration — add
banner_file_guid(varchar 36, nullable) tokickoff_competition. The upload becomes a coreFilerecord attached to the competition; the GUID column marks which attached file is the banner. (Core'sFile::$categoryis still marked experimental, so a dedicated column is preferred.)Model (
Competition)$bannerUploadattribute (yii\web\UploadedFile) with animagevalidation rule (extensions png/jpg/jpeg/webp, max size, optionally min dimensions).getBannerImageUrl(): ?string— uploaded file'sFile::getUrl()if set, elsebanner_image_url, elsenull.Form (
views/admin/_form.php) —enctype: multipart/form-data,fileInput()field, thumbnail preview of the current banner, "remove banner" checkbox.Controller (
AdminController::actionCreate/actionUpdate) —UploadedFile::getInstance()before save; on success create a coreFileUpload(setUploadedFile()→save()), attach to the competition, store the GUID; delete the previously attached file on replace/remove.Access control —
File::canView()delegates to the underlying record when it implementshumhub\interfaces\ViewableInterface.Competition::canView()already exists (v1.0.2 access gating); declare the interface and widen the signature tocanView($user = null). Restricted competitions' banners are then gated exactly like their pages. Without this, files attached to plain records are world-readable and would leak banners of restricted competitions.View (
views/competition/_banner.php) — use$competition->getBannerImageUrl()instead of readingbanner_image_urldirectly.Notes
Competition::afterDelete()to remove the banner file.UploadButtonwidget is not needed.banner_image_urluntouched) — nominVersionbump.