Usage

* * If you want to implement a FileField into a form element, you need to pass it an array of source data. * * * class ExampleForm_Controller extends Page_Controller { * * function Form() { * $fields = new FieldList( * new TextField('MyName'), * new FileField('MyFile') * ); * $actions = new FieldList( * new FormAction('doUpload', 'Upload file') * ); * $validator = new RequiredFields(array('MyName', 'MyFile')); * * return new Form($this, 'Form', $fields, $actions, $validator); * } * * function doUpload($data, $form) { * $file = $data['MyFile']; * $content = file_get_contents($file['tmp_name']); * // ... process content * } * } * * * @package forms * @subpackage fields-files */ class FileField extends FormField { /** * Flag to automatically determine and save a has_one-relationship * on the saved record (e.g. a "Player" has_one "PlayerImage" would * trigger saving the ID of newly created file into "PlayerImageID" * on the record). * * @var boolean */ public $relationAutoSetting = true; /** * Upload object (needed for validation * and actually moving the temporary file * created by PHP). * * @var Upload */ protected $upload; /** * Partial filesystem path relative to /assets directory. * Defaults to Upload::$uploads_folder. * * @var string */ protected $folderName = false; /** * Create a new file field. * * @param string $name The internal field name, passed to forms. * @param string $title The field label. * @param int $value The value of the field. */ public function __construct($name, $title = null, $value = null) { $this->upload = Upload::create(); parent::__construct($name, $title, $value); } public function Field($properties = array()) { $properties = array_merge($properties, array( 'MaxFileSize' => $this->getValidator()->getAllowedMaxFileSize() )); return parent::Field($properties); } public function getAttributes() { return array_merge( parent::getAttributes(), array('type' => 'file') ); } public function saveInto(DataObjectInterface $record) { if(!isset($_FILES[$this->name])) { return false; } $fileClass = File::get_class_for_file_extension( pathinfo($_FILES[$this->name]['name'], PATHINFO_EXTENSION) ); if($this->relationAutoSetting) { // assume that the file is connected via a has-one $hasOnes = $record->has_one($this->name); // try to create a file matching the relation $file = (is_string($hasOnes)) ? Object::create($hasOnes) : new $fileClass(); } else if($record instanceof File) { $file = $record; } else { $file = new $fileClass(); } $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName()); if($this->upload->isError()) { return false; } if($this->relationAutoSetting) { if(!$hasOnes) { return false; } $file = $this->upload->getFile(); $record->{$this->name . 'ID'} = $file->ID; } return $this; } public function Value() { return isset($_FILES[$this->getName()]) ? $_FILES[$this->getName()] : null; } /** * Get custom validator for this field * * @param Upload_Validator $validator */ public function getValidator() { return $this->upload->getValidator(); } /** * Set custom validator for this field * * @param Upload_Validator $validator * @return FileField Self reference */ public function setValidator($validator) { $this->upload->setValidator($validator); return $this; } /** * Sets the upload folder name * * @param string $folderName * @return FileField Self reference */ public function setFolderName($folderName) { $this->folderName = $folderName; return $this; } /** * Gets the upload folder name * * @return string */ public function getFolderName() { return ($this->folderName !== false) ? $this->folderName : Config::inst()->get('Upload', 'uploads_folder'); } public function validate($validator) { if(!isset($_FILES[$this->name])) return true; $tmpFile = $_FILES[$this->name]; $valid = $this->upload->validate($tmpFile); if(!$valid) { $errors = $this->upload->getErrors(); if($errors) foreach($errors as $error) { $validator->validationError($this->name, $error, "validation", false); } return false; } return true; } /** * Retrieves the Upload handler * * @return Upload */ public function getUpload() { return $this->upload; } /** * Sets the upload handler * * @param Upload $upload * @return FileField Self reference */ public function setUpload(Upload $upload) { $this->upload = $upload; return $this; } /** * Limit allowed file extensions. Empty by default, allowing all extensions. * To allow files without an extension, use an empty string. * See {@link File::$allowed_extensions} to get a good standard set of * extensions that are typically not harmful in a webserver context. * See {@link setAllowedMaxFileSize()} to limit file size by extension. * * @param array $rules List of extensions * @return $this */ public function setAllowedExtensions($rules) { $this->getValidator()->setAllowedExtensions($rules); return $this; } /** * Limit allowed file extensions by specifying categories of file types. * These may be 'image', 'audio', 'mov', 'zip', 'flash', or 'doc' * See {@link File::$allowed_extensions} for details of allowed extensions * for each of these categories * * @param string $category Category name * @param string,... $categories Additional category names * @return $this */ public function setAllowedFileCategories($category) { $extensions = array(); $knownCategories = File::config()->app_categories; // Parse arguments $categories = func_get_args(); if(func_num_args() === 1 && is_array(reset($categories))) { $categories = reset($categories); } // Merge all categories into list of extensions foreach(array_filter($categories) as $category) { if(isset($knownCategories[$category])) { $extensions = array_merge($extensions, $knownCategories[$category]); } else { user_error("Unknown file category: $category", E_USER_ERROR); } } return $this->setAllowedExtensions($extensions); } /** * Returns list of extensions allowed by this field, or an empty array * if there is no restriction * * @return array */ public function getAllowedExtensions() { return $this->getValidator()->getAllowedExtensions(); } }