0 follower

Tworzenie rozszerzeń

Ponieważ rozszerzenie zostało pomyślane do używania przez innych deweloperów, potrzeba dodatkowego wysiłku aby go stworzyć. Poniżej kilka ogólnych wskazówek:

  • Rozszerzenie powinno być samowystarczające. Oznacza to, jego zależności zewnętrzne powinny być minimalne. Rozszerzenie może przyprawić o ból głowy jeśli wymaga instalacji dodatkowych pakietów, klas lub plików.
  • Pliki należące do rozszerzenia powinny zostać zorganizowane w tym samym katalogi, którego nazwa jest identyczna jak nazwa rozszerzenia.
  • Klasy w rozszerzeniu powinny być poprzedzone pewną literą(ami) aby uniknąć konfliktów nazw z klasami z innych rozszerzeń.
  • Rozszerzenie powinno być dostarczone wraz ze szczegółowymi instrukcjami instalacyjnymi oraz udokumentowanym API. Zredukuje to czas i nakłady poświęcone przez innych programistów podczas używania rozszerzenia.
  • Rozszerzenie powinno używać odpowiedniej licencji. Jeśli chcesz uczynić twoje rozszerzenie dostępne zarówno dla projektów open-source jak i o kodzie zamkniętym powinieneś rozważyć używanie licencji takich jak BSD, MIT, itp. ale nie GPL, gdyż ta wymaga aby kod wywodził się od innego kodu open-source.

Następnie, opiszemy jak utworzyć nowe rozszerzenie, odpowiednio do katergori opisanych w przeglądzie. Opis ten również ma zastosowanie kiedy tworzysz komponenty do użytku we własnych projektach.

1. Komponent aplikacji

Komponent aplikacji powinien implementować interfejs IApplicationComponent lub dziedziczyć z CApplicationComponent. Główna metoda, która musi zostać zaimplementowana to IApplicationComponent::init, w której to komponent wykonuje pewną pracę początkową. Metoda ta jest wywoływana zaraz po tym jak komponent jest utworzony i wartości początkowe (określone w konfiguracji aplikacji) zostały nadane.

Domyślnie, komponent aplikacji jest tworzony i inicalizowany tylko wtedy, gdy żądamy dostępu do nie go po raz pierwszy podczas obsługiwania żądania. Jeśli komponent aplikacji musi być utworzony zaraz po tym jak instancja aplikacji została utworzona, powinien jedo ID zostać dodane do listy we właściwości CApplication::preload.

2. Zachowanie (ang. Behavior)

Aby utworzyć zachowanie nalezy zaimplementować interfejs IBehavior. Dla ułatwienia Yii dostarcza klasę bazową CBehavior, która już implementuje ten interfejs oraz dostarcza pewne dodatkowe, przydatne metody. Klasy potomne muszą głównie implementować dodatkowe metody, które zamierzamy udostepnić komponentom, do których dołączamy zachowanie.

Podczas tworzenia zachowań dla klas CModel oraz CActiveRecord, możemy odpowiednio rozszerzać odpowiadające im klasy zachowań CModelBehavior oraz CActiveRecordBehavior. Te bazowe klasy oferują dodatkowe funkcjonalności, które zostały stworzone specjalnie dla klas CModel oraz CActiveRecord. Na przykład klasa CActiveRecordBehavior implementuje zestaw metod, które odpowiadają zdarzeniom wywoływanym w obiekcie AR w trakcie jego cyklu życia. Metoda pochodna może zatem nadpisywać te metody, aby "wtrącić" dodatkowy kod, który będzie uczestniczyć w cyklu życia AR.

Następujący kod pokazuje przykład zachowanie dla rekordu aktywnego (AR). Kiedy takie zachowanie jest dołączane do obiektu AR oraz kiedy obiek AR jest zapisywany poprzez wywołanie metody save(), przypisze ono automatycznie atrybutom create_time oraz update_time wartość znacznika czasu (ang. timestamp).

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

3. Widżet

Widżet powinien dziedziczyć z klasy CWidget lub jej klas pochodnych.

Najprostszym sposobem utworzenia nowego widżetu jest rozszerzenie istniejącego widżetu oraz nadpisanie jego metod lub zmienienie jego domyślnych wartości własności. Na przykład, jeśli chcesz używać ładniejszego stylu dla klasy CTabView, powinieneś skonfigurować jej właściwość CTabView::cssFile jeśli używasz tego widżetu. Możesz również rozszerzyć klasę CTabView następująco, tak że nie będzie wymagane dłużej używanie konfiguracji tej właściwości podczas używania widżetu.

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();
    }
}

Powyżej, nadpisujemy metodę CWidget::init oraz przypisujemy URL do CTabView::cssFile naszego nowego stylu CSS jeśli właściwość nie jest ustawiona. Umieszczamy nowy plik stylu CSS w tym samym katalogu zawierającym plik klasy MyTabView, tak że mogą one być spakowane jako rozszerzenie. Ponieważ plik stylu CSS nie jest dostępny w sieci musimy go opublikować jako zasób.

Aby utworzyć nowy widżet od zera, musimy głównie zaimplementować dwie metody: CWidget::init oraz CWidget::run. Pierwsza metoda jest wołana kiedy używamy $this->beginWidget do wstawiania widżetu w widok a druga metoda jest wołana wtedy, gdy wołamy $this->endWidget. Jeśli chcemy przechwycić i przetworzyć zawartość wyświetlaną pomiędzy wywołaniami tych dwóch metod, możemy rozpocząć buforowanie wyjścia w CWidget::init oraz zwrócić zbuforowane wyjście w CWidget::run w celach dalszego przetwarzania.

Widżet często dołącza CSS, JavaScript lub inne pliki zasobów do strony, która używa widżetu. Nazywamy te pliki zasobami (ang. assets) ponieważ znajdują się razem z plikami klas widżetu i są zazwyczaj niedostępne dla internauty. Aby uczynić te pliki dostępnymi w sieci, musimy opublikować je używając CWebApplication::assetManager, tak jak pokazano w poniższym fragmencie kodu. Poza tym, jeśli chcemy dołączyć plik CSS lub JavaScript do aktualnej strony, musimy go zarejestrować używając CClientScript:

class MyWidget extends CWidget
{
    protected function registerClientScript()
    {
        // ...opublikuj tutaj pliki CSS lub JavaScript...
        $cs=Yii::app()->clientScript;
        $cs->registerCssFile($cssFile);
        $cs->registerScriptFile($jsFile);
    }
}

Widżet może również posiadać swój własny plik widoku. Jeśli tak, utwórz katalog nazwany views w katalogu zawierającym plik klasy widżetu i umieść w nim wszystkie pliki widoku. W klasie widżetu, w celu wygenerowania widoku widżetu użyj $this->render('ViewName'), co jest bardzo podobne do tego co robiliśmy w kontrolerze.

4. Akcja

Akcja powinna dziedziczyć z klasy CAction lub jej klas pochodnych. Główną metodą, która musi być zaimplementowana dla akcji to IAction::run.

5. Filtr

Filtr powinien dziedziczyć z CFilter lub jego klas pochodnych. Główne metody, które muszą zostać zaimplementowane dla filtru to CFilter::preFilter oraz CFilter::postFilter. Pierwsza jest wołana przed wywołaniem akcją gdy druga wołana jest po.

class MyFilter extends CFilter
{
    protected function preFilter($filterChain)
    {
        // logika stosowana przed wykonaniem akcji
        return true; // false if the action should not be executed
    }
 
    protected function postFilter($filterChain)
    {
        // logika stosowana po wykonaniu akcji
    }
}

Parametr $filterChain jest typu CFilterChain i zawiera informacje dotyczące akcji, któa jest aktualnie filtrowana.

6. Kontroler

Kontroler dystrybuowany jako rozszerzenie powinien dziedziczyć z CExtController, zamiast z CController. Głównym powodem jest to, że CController zakłada, że pliki widoku kontrolera znajdują się w application.views.ControllerID, gdy zaś CExtController zakłada, że pliki widoku znajdują się w katalogu views, który jest podkatalogiem katalogu zawierającego plik klasy kontrolera. Z tego też powodu, łatwiej można redystrybuować kontroler, ponieważ pliki widoku znajdują się razem z plikami klasy kontrolera.

7. Walidator

Walidator powinien dziedziczyć z CValidator i implementować swoją metodę CValidator::validateAttribute.

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

8. Konsola poleceń

Konsola poleceń powinna dziedziczyć z CConsoleCommand i implementować swoją metodę CConsoleCommand::run. Opcjonalnie, możemy nadpisać CConsoleCommand::getHelp aby dostarczyć trochę informacji dotyczących polecenia.

class MyCommand extends CConsoleCommand
{
    public function run($args)
    {
        // $args zwraca tablicę argumentów wiersza polecenia dla tego polecenia
    }
 
    public function getHelp()
    {
        return 'Używanie: jak używać tego polecenia';
    }
}

9. Moduł

Zerknij do sekcji dotyczącej modułów aby zobaczyć jak utworzyć moduł.

Ogólną wytyczną dla tworzenia moduły jest to, iż powinien on być samowystarczalny. Pliki zasobów (takie jak CSS, JavaScript, obrazki), które są używane w module, powinny być dystrybuowane razem z modułem, a moduł powinien opublikować jest, tak żeby były one dostępne dla internauty.

10. Generyczne komponenty

Tworzenie rozszerzeń generycznych komponentów to jak pianie klasy. Również tutaj, komponent powinien być samowystarczalny, tak że może ony być w łatwy sposób wykorzystany przez innych deweloperów.