Skip to content

FileUpload

One file per record and field, e.g. a contract. The file is stored like an attachment – same checks, virus scan and downloads – and belongs to the record and the field; there is no column.

use Anvil\Schema\Fields\FileUpload;
FileUpload::make('contract')->label('Contract (PDF)')->accept(['pdf'])->required(),
FileUpload::make('photo')->accept(['png', 'jpg', 'jpeg', 'webp'])->helperText('At most 10 MB.'),
Option Effect Default
accept(['pdf', …]) allowed extensions, a subset of Config\Anvil::$fileTypes (others throw an InvalidArgumentException); also the accept attribute of the input all of $fileTypes

Plus the options of every field. The field is always virtual; virtual(false) has no effect.

When the record is saved the file is checked like every upload, see Files:

  • the extension and the MIME type detected from the content must be allowed,
  • the size must not exceed $fileMaxSize (10 MB by default, see Maximum file size),
  • the virus scanner, if configured, must find it clean.

A rejected file fails the save with the reason at the field (422); the record is not saved (same transaction).

The limit is $fileMaxSize in bytes (default 10 MB) and applies to every upload of the application – file fields and attachments. There is no limit per field. Change it in app/Config/Anvil.php:

namespace Config;
use Anvil\Config\Anvil as BaseAnvil;
class Anvil extends BaseAnvil
{
public int $fileMaxSize = 25 * 1024 * 1024; // 25 MB
}

or per environment in .env (bytes):

anvil.fileMaxSize = 26214400

PHP and the web server have limits of their own and reject larger requests before Anvil sees the file (“The upload failed”). Raise them to at least the same size:

Where Setting
php.ini upload_max_filesize = 25M and post_max_size = 26M (a bit more: the request also holds the other fields)
nginx client_max_body_size 26m;
Apache LimitRequestBody (if set)
  • The current file is shown with name and size as a download link.
  • Choosing a new file replaces the old one.
  • Optional fields offer Remove file; required() fields need a file when created and cannot be emptied.
  • Forms with a file field are sent as multipart/form-data.

Nothing in the model. The file is stored with the owner record and the field name; service('files')->forField($ownerType, $id, 'contract') reads it in own code. Details: Files.

The input is checked when the file is stored, not by rules: required() is checked on saving (a file must exist or be uploaded).

The download link with name and size; downloads go through the file route with the permissions of the record.

Not part of the API (no multipart uploads).