How to Reuse File Upload Code via Behavior

hello guys now i am going to show you how to Reuse File Upload Code across multiple projects.

for to reuse this code now am going to create new Behavior called UploadBehavior under components directory that extends CActiveRecordBehavior this is because our Behavior work on events such as beforeSave() and beforeValidate().

class UploadBehavior extends CActiveRecordBehavior 
{

}

now create two public properties called $field and $paths one for attribute that accepts file uploads and another for path to save the uploaded file.

/**
 * name of the file field that this behavior manages
 */
 public $field = 'file';

/**
 * name of the path where uploaded files are saved
 * Note: path must not end with slash ( / )
 */
 public $path = 'assets';

now create beforeValidate() function that assigns uploaded file to the $field as

/**
 * load file instance before validates
 */
 public function beforeValidate($event)
 {
     $this->owner->{$this->field} = CUploadedFile::getInstance($this->owner, $this->field);
 }

now create beforeSave() function to save uploaded file to the $path

/**
 * check for file upload and save the file when uploaded
 */
public function beforeSave($event)
{
    // save file to $path when $field is not null
    if ($this->owner->{$this->field} !== null) {
        // assign the file name
        $file = $this->owner->{$this->field}->name;
        // save $file to the $path
        $this->owner->{$this->field}->saveAs($this->path . '/' . $file);
    }
}

now our Behavior is ready to reuse. the whole Class looks like this:

class UploadBehavior extends CActiveRecordBehavior 
{

    /**
     * name of the file field that this behavior manages
     */
    public $field = 'file';

    /**
     * name of the path where uploaded files are saved
     * Note: path must not end with slash ( / )
     */
    public $path = 'assets';

    /**
     * load file instance before validates
     */
     public function beforeValidate($event)
     {
         $this->owner->{$this->field} = CUploadedFile::getInstance($this->owner, $this->field);
     }

    /**
     * check for file upload and save the file when uploaded
     */
    public function beforeSave($event)
    {
        // save file to $path when $field is not null
        if ($this->owner->{$this->field} !== null) {
            // assign the file name
            $file = $this->owner->{$this->field}->name;
            // save $file to the $path
            $this->owner->{$this->field}->saveAs($this->path . '/' . $file);
        }
    }
}

now it is time for Action. attach this behavior to your model like this:

for this example you can use Post model of Blog demo. in real time it can be any of your model that allows file uploads.

// Post.php
public function behaviors()
{
    return array(
        'upload'=>array(
            // set class name
            'class'=>'UploadBehavior',
            // name of the attribute that receives file upload
            'field'=>'image',
            // name of the path to save uploaded file
            'path'=>'images', // Note: trailing slash(/) is not required. here we save our file into images
        )
    );
}

that's all. from now we can reuse this behavior across multiple projects without rewriting the similar code for every file upload.

Note: the above example shows you how to manage single file upload only. you can slightly rewrite the above behavior to accept multiple file uploads.

Extending this Behavior: this behavior can be further extended such as uploading file with unique file name, delete previous file when new file is uploaded, delete the uploaded file when parent record is deleted.

Download this behavior: you can download this behavior from here

Suggestions and Feedbacks: you can suggest your ideas and feedback regarding this.

                                                                              -Thank you