Files
yii/docs/guide/de/extension.create.txt
2009-11-01 17:58:27 +00:00

269 lines
10 KiB
Plaintext

Erweiterungen erstellen
=======================
Da eine Erweiterung auch von anderen Entwicklern verwendet werden soll,
erfordert ihre Erstellung etwas zusätzlichen Aufwand. Hier einige
grundsätzliche Richtlinien:
* Eine Erweiterung sollte in sich geschlossen sein. Das heisst, sie sollte
möglichst wenig externe Abhängigkeiten aufweisen. Für einen Anwender wäre es
sehr lästig, wenn er für eine Erweiterung erst zusätzliche Pakete, Klassen
oder sonstige Dateien installieren müsste.
* Alle Dateien, die zu einer Erweiterung gehören, sollten unterhalb des
Verzeichnisses mit dem Namen der Erweiterung abgelegt werden.
* Klassen in einer Erweiterung sollte ein Buchstabe (bzw. mehrere Buchstaben)
vorangestellt sein, um Konflikte mit Klassen von anderen Erweiterungen zu
vermeiden.
* Eine Erweiterung sollte eine detaillierte Installationsanleitung und
API-Dokumentation enthalten. So können Zeit und Aufwand für andere
Entwickler minimiert werden, wenn sie die Erweiterung verwenden möchten.
* Eine Erweiterung sollte ein passende Lizenz verwenden. Wenn Ihre Erweiterung
sowohl in Open-Source- als auch in Closed-Source-Projekten (Projekte mit
einsehbarem bzw. nicht einsehbarem Quellcode) einsetzbar sein
soll, könnten Sie Lizenzen wie BSD oder MIT in die engere Wahl ziehen. GPL
allerdings nicht, da bei ihr auch jeglicher davon abgeleitete Code als
Open Source zur Verfügung gestellt werden muss.
Wir beschreiben im Folgenden, wie Sie eine neue Erweiterung entsprechend den
Kategorien in der [Übersicht](/doc/guide/extension.overview) erstellen können.
Die Erläuterungen sind auch für Erweiterungen gültig, die Sie hauptsächlich
für Ihre eigenen Projekt erstellen.
Anwendungskomponente
--------------------
Eine
[Anwendungskomponente](/doc/guide/basics.application#application-component)
sollte das Interface [IApplicationComponent] implementieren oder die Klasse
[CApplicationComponent] erweitern. Die wichtigste zu implementierende Methode
ist [IApplicationComponent::init], in der die Komponente ihre Initialisierung
vornehmen kann. Diese Methode wird aufgerufen, nachdem die Komponente erstellt
und ihr die Startwerte ihrer Eigenschaften (entsprechend der
[Anwendungskonfiguration](/doc/guide/basics.application#application-configuration))
zugewiesen wurden.
Standardmäßig wird eine Komponente nur erstellt und initialisiert, wenn zum
ersten mal auf sie zugegriffen wird. Falls eine Anwendungskomponente
unmittelbar nach der Anwendungsinstanz erzeugt werden muss, sollte der
Anwender sie in der Eigenschaft [CApplication::preload] aufführen.
Behavior
--------
Um ein Behavior zu erstellen, muss das [IBehavior]-Interface implementiert
werden. Bequemerweise enthält Yii bereits die Basisklasse [CBehavior],
die dieses Interface implementiert und einige weitere Komfortfunktionen
anbietet. Kindklassen müssen hauptsächlich die Methoden implementieren, die
sie ihren Komponenten bereitstellen wollen.
Wenn man Behaviors für [CModel] und [CActiveRecord] entwickeln möchte, kann
man auch [CModelBehavior] bzw. [CActiveRecordBehavior] erweitern. Diese
Basisklassen bieten zusätzliche, an [CModel] bzw. [CActiveRecord] angepasste
Features. Die [CActiveRecordBehavior]-Klasse implementiert z.B. eine Reihe von
Methoden, die auf die Events im Lebenszyklus eines ActiveRecord-Objekts
reagieren. Eine Kindklasse kann diese Methoden überschreiben, um so
angepassten Code einzuschleusen, der im Lebenszyklus eines AR ausgeführt wird.
Der folgende Code zeigt ein Beispiel eines ActiveRecord-Behaviors. Wenn dieses
Behavior an ein AR-Objekt angebunden und dann dessen `save()`-Methode
aufgerufen wird, setzt es automatisch die Attribute `create_time` und
`update_time` auf den aktuellen Zeitstempel.
~~~
[php]
class TimestampBehavior extends CActiveRecordBehavior
{
public function beforeSave($event)
{
if($this->owner->isNewRecord)
$this->owner->create_time=time();
else
$this->owner->update_time=time();
}
}
~~~
Widget
------
Ein [Widget](/doc/guide/basics.view#widget) sollte [CWidget] oder dessen
Kindklassen erweitern.
Am einfachsten erstellt man ein Widget, indem man ein vorhandenes Widget
erweitert und seine Methoden oder vorgegebenen Eigenschaften überschreibt.
Wenn Sie z.B. schönere CSS-Stile für [CTabView] verwenden möchten, könnten Sie
dessen [CTabView::cssFile]-Eigenschaft konfigurieren. Sie könnten [CTabView]
aber auch wie im folgenden Beispiel erweitern, so dass Sie diese Eigenschaft
beim Einsatz des Widgets nicht mehr angeben müssen.
~~~
[php]
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();
}
}
~~~
Hier überschreiben wir die Methode [CWidget::init] und weisen
[CTabView::cssFile] die URL für unsere neue CSS-Datei zu, falls diese
Eigenschaft noch nicht gesetzt war. Wir legen die neue CSS-Datei im selben
Verzeichnis ab, das auch die Klassendatei von `MyTabView` enthält, damit beide als
Erweiterung zusammengepackt werden können. Da die CSS-Datei vom Web aus nicht
zugänglich ist, müssen wir sie als Asset veröffentlichen.
Um ein ganz neues Widget zu erstellen, müssen wir hauptsächlich zwei Methoden
implementieren: [CWidget::init] und [CWidget::run]. Erstere wird aufgerufen,
wenn wir `$this->beginWidget` verwenden, um ein Widget in einem View
einzusetzen, die Zweite, wenn wir `$this->endWidget` aufrufen. Falls wir den
eingebetteten Inhalt zwischen den beiden Aufrufen abfangen und verarbeiten
möchten, können wir in [CWidget::init] eine
[Ausgabepufferung](http://de3.php.net/manual/de/book.outcontrol.php)
starten und die gepufferte Ausgabe in [CWidget::run] zur weiteren
Bearbeitung auslesen.
Ein Widget erfordert oftmals die Einbindung von CSS-, Javascript- oder anderen
Dateien in eine Seite. Diese Dateien nennen wir *Assets* (sinngem.: Anlage,
Zusatz), da sie am Ort der Widget-Klasse abgelegt werden und normalerweise für
Web-Besucher nicht erreichbar sind. Um diese Dateien vom Web aus zugänglich zu
machen, müssen wir sie mit [CWebApplication::assetManager] (sinngem.:
Anlagenverwalter) veröffentlichen, wie im obigen Codebeispiel gezeigt. Wenn
wir eine CSS- oder Javascript-Datei außerdem in die aktuelle Seite einbinden
möchten, müssen wir sie mit [CClientScript] registrieren:
~~~
[php]
class MyWidget extends CWidget
{
protected function registerClientScript()
{
// ...CSS- oder Javascript-Datei hier veröffentlichen...
$cs=Yii::app()->clientScript;
$cs->registerCssFile($cssFile);
$cs->registerScriptFile($jsFile);
}
}
~~~
Ein Widget kann auch seine eigenen View-Dateien verwenden. In diesem Fall
legen Sie ein Verzeichnis namens `views` unterhalb des Ordners an, der die
Klassendatei des Widgets enthält. Legen Sie alle zugehörigen View-Dateien dort ab.
Ähnlich wie im Controller können Sie dann in der Widget-Klasse
`$this->render('ViewName')` benutzen, um einen View zu rendern.
Action
------
Eine [Action](/doc/guide/basics.controller#action) sollte [CAction] oder deren
Kindklassen erweitern. Die wichtigste zu implementierende Methode für eine
Action ist [IAction::run].
Filter
------
Ein [Filter](/doc/guide/basics.controller#filter) sollte von [CFilter] oder
dessen Kindklassen abgeleitet werden. Die beiden wichtigsten zu
implementierenden Methoden für einen Filter sind [CFilter::preFilter] und
[CFilter::postFilter]. Erstere wird aufgerufen, bevor eine Action ausgeführt
wird, letztere danach.
~~~
[php]
class MyFilter extends CFilter
{
protected function preFilter($filterChain)
{
// Logik, die vor dem Aufruf der Action ausgeführt wird
return true; // false, falls die Action nicht ausgeführt werden soll
}
protected function postFilter($filterChain)
{
// Logik, die nach dem Aufruf der Action ausgeführt wird
}
}
~~~
Der Parameter `$filterChain` (Filterkette) ist vom Typ [CFilterChain] und
enthält Informationen über die gerade zu filternde Action.
Controller
----------
Wenn ein [Controller](/doc/guide/basics.controller) als Erweiterung
veröffentlicht werden soll, sollte er [CExtController] statt [CController]
erweitern. Und zwar hauptsächlich deshalb, weil ein [CController] seine
View-Dateien unter `application.views.ControllerID` sucht, während
[CExtController] seine View-Dateien im Unterverzeichnis `views` des Ordners
erwartet, der auch die Klassendatei des Controllers enthält. Dadurch wird es
einfacher, den Controller weiterzugeben, da seine View-Dateien bei der
Klassendatei verbleiben.
Validator
---------
Ein Validator sollte [CValidator] erweitern und dessen Methode
[CValidator::validateAttribute] implementieren.
~~~
[php]
class MyValidator extends CValidator
{
protected function validateAttribute($model,$attribute)
{
$value=$model->$attribute;
if($value has error)
$model->addError($attribute,$errorMessage);
}
}
~~~
Konsolenbefehl
--------------
Ein [Konsolenbefehl](/doc/guide/topics.console) sollte [CConsoleCommand]
erweitern und dessen Methode [CConsoleCommand::run] implementieren. Optional
können wir auch [CConsoleCommand::getHelp] überschreiben, um eine nützliche
Hilfe zum Befehl anzuzeigen.
~~~
[php]
class MyCommand extends CConsoleCommand
{
public function run($args)
{
// $args ist ein Array mit den Kommandozeilenargumenten dieses Befehls
}
public function getHelp()
{
return 'Anleitung: Wie Sie diesen Befehl verwenden';
}
}
~~~
Module
------
Für Details zur Erstellung von Modulen, beachten Sie bitte das Kapitel über
[Module](/doc/guide/basics.module#creating-module).
Die allgemeine Richtlinie für die Entwicklung eines Moduls lautet: Es sollte in
sich geschlossen sein. Sämtliche Dateien, die vom Modul verwendet werden (wie
z.B. CSS-, Javascript-, Bilddateien) sollten zusammen mit dem Modul geliefert
werden. Und sie sollten vom Modul veröffentlicht werden, um sie vom Web aus
zugänglich zu machen.
Allgemeine Komponenten
----------------------
Eine allgemeine Erweiterungskomponente zu entwickeln, bedeutet, eine Klasse zu
schreiben. Auch hier gilt: Die Komponente sollte in sich geschlossen sein, so
dass sie von anderen Entwicklern einfach eingesetzt werden kann.
<div class="revision">$Id: extension.create.txt 1423 2009-09-28 01:54:38Z qiang.xue $</div>