Creare estensioni

Quanto segue, sono le linee guida per lo sviluppo di estensioni per Yii.

  • Bisogna cercare di rendere le estensioni indipendenti da altro codice. La dipendenza da altre classi, estensioni o pacchetti, potrebbe rendere difficoltosa la loro installazione per gli utenti che desiderano utilizzarle.
  • Tutti i file di una stessa estensione, dovrebbero essere organizzati sotto la stessa cartella al fine di mantenere il codice il più ordinato possibile.
  • Le classi in una estensione dovrebbero avere lo stesso prefisso onde evitare conflitti con i nomi di classi di altre estensioni.
  • È importante fornire l'estensione di una corretta documentazione. Questo serve a ridurre il tempo necessario agli altri sviluppatori per usare questa estensione.
  • Un'estensione deve usare una licenza appropriata. Se vuoi rendere la tua estensione utilizzabile sia in progetti open-source che in progetti closed-source. Puoi considerare di usare la licenza BSD, MIT, etc. Ma non la licenza GPL che richiede che i progetti derivati siano open-source a loro volta.

Di seguito, si descrive come creare una nuova estensione, secondo le linee guida che si possono leggere nell'overview. È consigliato seguire le linee guida anche nei propri progetti, quando i componenti che si vanno a creare non vengono pubblicati sul sito di Yii.

1. Component dell'applicazione

Un component dell'applicazione può implementare l'interfaccia IApplicationComponent oppure estendere la classe CApplicationComponent. Il metodo principale da implementare è il metodo IApplicationComponent::init nel quale il componente esegue il suo lavoro di inizializzazione. Questo metodo viene invocato dopo che il componente è stato creato ed i valori iniziali (come spiegato nella configurazione dell'applicazione) sono applicati.

Di default, un component dell'applicazione è creato ed inizializzato solo quando viene caricato la prima volta. Se un component dell'applicazione necessita di essere caricato prima dell'istanziazione dell'applicazione, si può indicare il suo ID nella proprietà CApplication::preload.

2. Behavior

Per creare un behavior, bisogna implementare l'interfaccia IBehavior. Per convenienza, Yii fornisce una classe base chiamata CBehavior che implementa già questa interfaccia e fornisce alcuni metodi aggiuntivi che possono farci comodo.

Quando si sviluppa un behavior per CModel o CActiveRecord, si può anche estendere CModelBehavior o CActiveRecordBehavior. Queste classi base offrono caratteristiche aggiuntive che sono specificatamente create per CModel e CActiveRecord. Per esempio, la classe CActiveRecordBehavior implementa un set di metodi per rispondere al ciclo di vita degli eventi scatenati da un oggetto ActiveRecord. Una classe figlia può sovrascrivere questi metodi per inserire del codice personalizzato.

Il codice seguente mostra un esempio di un behavior ActiveRecord. Quando questo behavior è collegato ad un oggetto ActiveRecord e quando questo oggetto salva utilizzando il metodo save, questo behavior esegue delle azioni automaticamente.

class TimestampBehavior extends CActiveRecordBehavior
{
    public function beforeSave($event)
    {
        if($this->owner->isNewRecord)
            $this->owner->create_time=time();
        else
            $this->owner->update_time=time();
    }
}

3. Widget

Un widget può estendere dalla classe CWidget o da sue classi figlie.

Il metodo più semplice di creare un nuovo widget è quello di estendere un Widget già esistente sovraccaricando i suoi metodi o cambiando le sue proprietà di default. Per esempio se si vuole usare un CSS differente per CTabView si può configurare la sua proprietà CTabView::cssFile. Si può anche estendere CTabView come mostrato di seguito, così da non aver bisogno di configurare la proprietà usando il widget.

class MyTabView extends CTabView
{
    public function init()
    {
        if($this->cssFile===null)
        {
            $file=dirname(__FILE__).DIRECTORY_SEPARATOR.'tabview.css';
            $this->cssFile=Yii::app()->getAssetManager()->publish($file);
        }
        parent::init();
    }
}

Nel codice precedente, vine sovrascritto il metodo CWidget::init ed assegnato alla proprietà CTabView::cssFile l'indirizzo del nostro nuovo foglio di stile (se la proprietà non è già stata impostata). Mettiamo il nuovo css nella stessa directory che contiene la classe MyTabView, in questo modo possono essere pacchettizzate come una estensione. Siccome il css non è accessibile al web, abbiamo bisogno di pubblicarlo dentro ad un asset.

Per creare un nuovo widget da zero, abbiamo principalmente bisogno di implementare due metodi: CWidget::init e CWidget::run. Il primo è chiamato quando noi usiamo $this->beginWidget. Il secondo quando viene chiamato $this->endWidget. Se vogliamo catturare e processare il contenuto mostrato tra l'invocazione di questi due metodi, possiamo iniziare l'output buffering dentro a CWidget::init e recuperare l'output bufferizzato dentro al metodo CWidget::run.

Un widget spesso include un css, del codice javascript ed altre risorse. Chiamiamo questi file assets perché loro stanno tutti raccolti con la classe del widget e solitamente non sono accessibili all'utente web. Per rendere questi file accessibili al web, abbiamo bisogno di pubblicarli usando CWebApplication::assetManager. Come mostrato nello snippet di codice, per registrare uno script dobbiamo utilizzare CClientScript:

class MyWidget extends CWidget
{
    protected function registerClientScript()
    {
        // ...publish CSS or JavaScript file here...
        $cs=Yii::app()->clientScript;
        $cs->registerCssFile($cssFile);
        $cs->registerScriptFile($jsFile);
    }
}

Un widget può anche avere un proprio file view. Se deve essere così, è necessario creare una directory chiamata views dentro alla directory contenente la classe del widget. Nella classe del widget, per renderizzare la view, bisogna utilizzare il metodo $this->render('ViewNamÈ) che è simile a quello che viene utilizzato in un controller.

4. Action

Una action può estendere la classe CAction oppure una sua classe figlia. Il metodo principale che deve essere implementato per una azione è IAction::run.

5. Filter

Un filter può estendere la classe CFilter o una sua classe figlia. Il metodo principale che deve essere implementato per un filter è CFilter::preFilter e CFilter::postFilter. Il primo viene invocato prima che l'action sia eseguita. Il secondo dopo.

class MyFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // logica che viene applicata prima che l'action venga eseguita
        return true; // false qualora l'action non debba essere eseguita
    }
 
    protected function postFilter($filterChain)
    {
        // logica che viene applicata dopo che l'action venga eseguita
    }
}

Il parametro $filterChain è di tipo CFilterChain che contiene informazioni riguardo l'action che è filtrata in questo momento.

6. Controller

Un controller distribuito come una estensione è un'estensione che può estendere CExtController, invece che CController. La ragione principale sta nel fatto che CController considera come file di view i file posizionati sotto la cartella application.views.ControllerID, mentre CExtController considera le view che si trovano sotto la cartella views che è una sottodirectory che contiene la classe del controller. In questo modo è facile ridistribuire il controller insieme ai suoi file view.

7. Validator

Un variatore può estendere la classe CValidator ed implementare il suo metodo CValidator::validateAttribute.

class MyValidator extends CValidator
{
    protected function validateAttribute($model,$attribute)
    {
        $value=$model->$attribute;
        if($value has error)
            $model->addError($attribute,$errorMessage);
    }
}

8. Console Command

Un console command può estendere la classe CConsoleCommand ed implementare il suo metodo CConsoleCommand::run. Opzionalmente, possiamo sovraccaricare anche il metodo CConsoleCommand::getHelp per fornire alcune informazioni di aiuto del comando.

class MyCommand extends CConsoleCommand
{
    public function run($args)
    {
        // $args gives an array of the command-line arguments for this command
    }
 
    public function getHelp()
    {
        return 'Usage: how to use this command';
    }
}

9. Modulo

Fate riferimento alla sezione moduli.

Una linea guida generale per sviluppare un modulo è che dovrebbe essere autosufficiente. I file di risorsa (come CSS, Javascript ed immagini) che sono usati da un modulo dovrebbero essere distribuiti insieme al modulo. Ed il modulo dovrebbe pubblicarli in modo tale che siano accessibili via web.

10. Component generico

Sviluppare un component generico è come scrivere una classe. Il component, può anche essere indipendente ed usato anche da altri sviluppatori.

$Id: extension.create.txt 1423 2009-09-28 01:54:38Z qiang.xue $

Be the first person to leave a comment

Please to leave your comment.