File uploads in CForm (Form builder)

While there is a reasonable amount of documentation regarding CForm (form builder) and file uploads seperately, there really is not any coverage of both in combination.

The Model

First you will need a model: (FileUpload.php)

<?php

class FileUpload extends CFormModel {

	public $image;

	/**
	 * @return array validation rules for model attributes.
	 */
	public function rules() {
		return array(
			//note you wont need a safe rule here
			array('image', 'file', 'allowEmpty' => true, 'types' => 'jpg, jpeg, gif, png'),
		);
	}

}

Note: for more information about validation rules, check Reference: Model rules validation

The CForm Array

Now you can build your CForm array: (uploadForm.php)

<?php

return array(
	'title' => 'Upload your image',

	'attributes' => array(
		'enctype' => 'multipart/form-data',
	),

	'elements' => array(
		'image' => array(
			'type' => 'file',
		),
	),

	'buttons' => array(
		'reset' => array(
			'type' => 'reset',
			'label' => 'Reset',
		),
		'submit' => array(
			'type' => 'submit',
			'label' => 'Upload',
		),
	),
);
The View

Your View: (upload.php)

<?php if (Yii::app()->user->hasFlash('success')): ?>
	<div class="info">
		<?php echo Yii::app()->user->getFlash('success'); ?>
	</div>
<?php endif; ?>

<h1>Image Upload</h1>
 
<div class="form">
<?php echo $form; ?>
</div>
The Controller

And a controller and action:

<?php

class FileUploadController extends CController {

	public function actionUpload() {
		$model = new FileUpload();
    $form = new CForm('application.views.fileUpload.uploadForm', $model);
		if ($form->submitted('submit') && $form->validate()) {
			$form->model->image = CUploadedFile::getInstance($form->model, 'image');
			//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			//do something with your image here
			//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			Yii::app()->user->setFlash('success', 'File Uploaded');
			$this->redirect(array('upload'));
		}
		$this->render('upload', array('form' => $form));
	}
}

At this point as best practice you would perform some work on the image in a method you write and call as a part of your FileUpload model. Note you don't have to assign anything to FileUpload::image but I do as a way of accessing it and having fat models/skinny controllers.