mirror of
https://github.com/yiisoft/yii.git
synced 2026-03-19 06:26:54 +01:00
269 lines
10 KiB
Plaintext
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>
|