Yii2.0 Behaviors的基本用法

簡介

Behavior顧名思義,即使一種行為,準確的說是類的行為。目的用于功能擴展。注意,這里用了擴展,擴展意味著是在原有的基礎上擴展,不同于從父類那里繼承而來。請注意琢磨這個特點,清楚了功能擴展有利于判斷清楚什么時候使用behavior。舉個例子,假如有一個類被定義為人,那么一些最基本的人的元素,如胳膊、腿、大腦等,就適合定義在自身里邊,或者從父類那里繼承而來。而一些附加的能力,如彈琴畫畫,就適合集成擴展。當然,你如果非喜歡用搭積木的方式生成一個人,就像定義一個胳膊的behavior、一個腿的behavior等,然后組裝成為一個人。可行性上講,那也可以,但是這樣就有點屬于濫用。

PHP中有traits,與behavior有點類似。但是traits更像是把一段代碼生硬地插進來,有點像C語言里的include。所以traits不能像behavior一樣在運行時加入。同樣不能對要加入的功能進行參數設置,類似這樣:

 public function behaviors() {
        return [
            TimestampBehavior::className(),
            [
                'class' => AttachmentsBehavior::className(),
                'uploadFiles' => 'attachmentsToBe',
                'uploadedFiles' => 'attachments',
            ]
        ];
    }

在這里對AttachmentsBehavior的兩個屬性進行了設置。這非常有用,比如對于同一個衣服behavior,大人需要大碼,小孩需要小碼,而用traits是很難做到的。說白了,traits是一個代碼片段,而behavior是一個類,功能更為強大。

用法

我在編寫一個網站時遇到了這樣一個情景,網站中有新聞和商城兩大板塊,要求對新聞與商城的商品都能上傳附件。心中一喜,這不正是用behavior的大好時機?附件對于新聞與商城來講都是可有可無的擴展功能。于是定義了新聞model、商品Model,以及attachmentBehavior。如下:

class News extends  \yii\db\ActiveRecord
{
//behavior就是上一段代碼,在此不再贅述
}
class Goods extends  \yii\db\ActiveRecord
{
//behavior如前
}

class AttachmentsBehavior extends Behavior {

    private $_files;
    /**
     * 需要上傳的文件屬性
     * @var string
     */
    public $uploadFiles = 'uploadfiles';
    /**
     * 已經上傳了的文件屬性
     * @var string
     */
    public $uploadedFiles = 'uploadedfiles';

    /**
     * 保存路徑
     * @var string
     */
    public $savePath = '@common/upload';

    /**
     * 訪問路徑
     * @var string
     */
    public $saveUrl = '@commonurl/upload';

    public function events() {
        return [
            BaseActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
            BaseActiveRecord::EVENT_AFTER_INSERT => 'afterSave',
            BaseActiveRecord::EVENT_AFTER_UPDATE => 'afterSave',
            BaseActiveRecord::EVENT_BEFORE_DELETE => 'beforeDelete',
        ];
    }

    /**
     * This method is invoked before validation starts.
     */
    public function beforeValidate()
    {
       $this->_files = UploadedFile::getInstances($this->owner, $this->uploadFiles);
    }

    /**
     * 返回擁有者的唯一Id
     * @return string
     */
    public function getIdentityId(){
        return  $this->owner->className().'.'.$this->owner->id;
    }

    /**
     * 明確擁有者與附件的關系
     * @return mixed
     */
    public function getAttachments(){
        return $this->owner->hasMany(Attachments::className(),['ownerId' => 'identityId']);
    }

    /**
     * 在主模型保存后挨個保存附件
     */
    public function afterSave(){

        foreach ($this->_files as $file){
            $model = new Attachments();
            $model->fileName = $file->name;
            $model->url = date('Ymd') . Yii::$app->getSecurity()->generateRandomString(8) .'.'. $file->extension;
            $model->ownerId = $this->owner->identityId;
            $model->savePath = Yii::getAlias($this->savePath);
            $file->saveAs(Yii::getAlias($this->savePath) . DIRECTORY_SEPARATOR .$model->url);
            $model->save();
        }

    }

    /**
     * 在主模型刪除之前刪除所有附件
     * @return bool
     */
    public function beforeDelete(){

        foreach ($this->owner->{$this->uploadedFiles} as $file){
            $file->delete();
        }
        return true;
    }


    public function getFilesUrl($url){
        return Yii::getAlias($this->saveUrl) . DIRECTORY_SEPARATOR. $url;
    }

}

在這里我特別把附件behavior的所有源碼都貼上了,原因有二、1、這個Behavior基本上用到了所有behavior常要用到的東西,2、文件上傳是我們常用的一個功能。詳解如下:

  • 一定要繼承yii的Behavior類。Behavior需要與Component配合使用,這里news和goods繼承了activerecord。activerecord是繼承了component的。
  • public屬性可以被配置,private不能被配置
  • 在Behavior中$this->owner表示父類,準確的說是父對象。所以,例如要獲得父類的類名稱,采用$this->owner->className()。
  • 在Behavior中可以定義多種event,這些事件的觸發與父類中的觸發時間一致。特別的是需要手動綁定。而不像父類中afterSave等已經自動綁定。我想,這是由于有些Behavior是不與model所綁定的。
  • 在Behavior中要訪問數據庫,需要通過model。就像在afterSave函數中所定義的那樣。

結束語

Behavior極大的增強了yii2的靈活性,這里僅展示了Behavior與model的結合,常常我們也會把Behavior與Controller結合,但是要注意,在于Controller結合時,Behavior中定義的action在Controller中不會被自動索引到,亦需要手動指定。所以,僅僅為了增加action,最好采用yii2中單獨action的復用方法。

多多琢磨Behavior,能夠極大的節約開發量,提升我們的開發效率,并且增強擴展性維護性。況且,很多現成的功能模塊都是利用Behavior而形成的,就奔著用好別人的勞動成果也要多學學Behavior。Good luck!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容