symfony1.2でDoctrine1.1使ってJobeetチュートリアル20日目
ついに20台まで来たよ。
pluginの説明とjobeetをplugin化しようの回。
subversionでバージョン管理している場合は、s/mv/svn mv/ で移動を明示的にして行方不明になるのを防ぎませう。
行方不明にしちゃった場合は、行方不明になったファイルをまとめて消すを使うと削除が楽です。
移動・削除の嵐で混乱してきたので、かみ砕いて訳してみます。個人的なメモは、オレンジで書いときます。
Previously on Jobeet
昨日は、symfonyのアプリを国際化・地域言語化する方法を学びましたね。ヘルパーとか使ったから簡単だったね。
今日は、pluginについて説明するよ。pluginとは何か?どうやってplugin化するか?どんな利用が可能か?
Plugins
A symfony Plugin
symfonyのpluginは、プロジェクトのファイル群の一部をパッケージ化して分配する方法を提供します。プロジェクト同様pluginは、classes, helpers, configuration, tasks, modules, schemas, そしてwebファイルを有しています。
Private Plugins
pluginの利用形態としては、あなたのアプリ間、もしくは、異なるプロジェクト間でのコード共有です。symfonyのアプリが共有しているのはmodelだけですか?pluginはより多くの部品をアプリ間で共有する方法を提供します。
もし、異なるプロジェクト間でschemaもしくはmoduleを使い回す必要があるとき、それらをpluginに移動させましょう。pluginといっても、ただのディレクトリです。svnのリポジトリを作りsvn:externals(外部定義)を編集、もしくは単純にコピーすることで、使い回すことができます。
我々は、これらの利用形態を"Private Plugins"と呼びます。なぜなら、このような利用方法は、単一の開発者や会社に限られるからです。オープンじゃないよ。
Private Pluginsでも、plugin channelに登録すれば、plugin:installタスクが利用できるよ。
Public Plugins
"Public Plugins"は誰もがdownloadしてinstall可能です。今回のチュートリアルでは、sfDoctrineGuardPlugin と sfFormExtraPluginの二つのPublic Pluginsを使います。
後ほど、symfonyのウェブサイトに自分のpluginを掲載する方法を学びます。
A Different Way to Organize Code
pluginの利用形態として、もう一つ考えられます。再利用性、共有について考えないのであれば、pluginは、コード整理として使えます。ファイルをレイヤーでまとめる代わりに、機能でまとめるのです。
Plugin File Structure
pluginは、まとめられたファイルによって構成された、ただのディレクトリで、その配置は自然なものとなっている。今日は、Jobeetとして書いてきた殆どのコードをsfJobeetPluginへと移動させます。ベースのレイアウトはこんな感じです。
sfJobeetPlugin/ config/ sfJobeetPluginConfiguration.class.php // Plugin initialization schema.yml // Database schema routing.yml // Routing lib/ Jobeet.class.php // Classes helper/ // Helpers filter/ // Filter classes form/ // Form classes model/ // Model classes task/ // Tasks modules/ job/ // Modules actions/ config/ templates/ web/ // Assets like JS, CSS, and images
The Jobeet Plugin
pluginsディレクトの下にsfJobeetPluginディレクトリを作成しましょう。
$ mkdir plugins/sfJobeetPlugin
plugin名は、pluginで終わるようにしましょう。また、sfで始まる習慣がありますが強制ではありません。
要は、sfHogePluginにしろと
The Model
まず、config/doctrine/schema.yml を plugins/sfJobeetPlugin/config/ に移動させます。
$ mkdir plugins/sfJobeetPlugin/config/ $ mv config/doctrine/schema.yml plugins/sfJobeetPlugin/config/doctrine/schema.yml
全てのコマンドは、Unixライクな環境のものです。Windows使っている場合は、ドラッグ&ドロップで移動させてください。
そして、Subversionやその他のコード管理ツールを使用している場合は、組み込みコマンドを利用して移動させてください。
Subversionなら、svn mvコマンドね
doctrineフォルダ作り忘れてるので、mvで怒られます。1つ1つちまちま作るのもめんどうなので、
$ mkdir -p plugins/sfJobeetPlugin/config/doctrine
pオプションつけて、一気に作ると楽です。
$ svn mkdir
コマンドもあるのですが、pオプションが無く、後でsvn addすればいいのでmkdirで問題ないです。
model, form, and filterのファイルを plugins/sfJobeetPlugin/lib/ に移動させてください。
$ mkdir plugins/sfJobeetPlugin/lib/ $ mv lib/model/ plugins/sfJobeetPlugin/lib/ $ mv lib/form/ plugins/sfJobeetPlugin/lib/ $ mv lib/filter/ plugins/sfJobeetPlugin/lib/
移動し終えたら、クラス名の頭にPluginを付けましょう。
例は、JobeetAffiliateクラスをリネームしています。
$ mv plugins/sfJobeetPlugin/lib/model/doctrine/JobeetAffiliate.class.php plugins/sfJobeetPlugin/lib/model/doctrine/PluginJobeetAffiliate.class.php
コード中のクラス名もリネームします。
<?php abstract class PluginJobeetAffiliate extends BaseJobeetAffiliate { public function preValidate($event) { $object = $event->getInvoker(); if (!$object->getToken()) { $object->setToken(sha1($object->getEmail().rand(11111, 99999))); } } // ... }
JobeetAffiliateTableクラスも同様に、処理していきます。
$ mv plugins/sfJobeetPlugin/lib/model/doctrine/JobeetAffiliateTable.class.php plugins/sfJobeetPlugin/lib/model/doctrine/PluginJobeetAffiliateTable.class.php
クラスの宣言は、この様に
<?php class PluginJobeetAffiliateTable extends Doctrine_Table { // ... }
formsとfilterのクラスにも同様の処理をします。クラス名の頭にPluginを付けます。
BaseFormDoctrine.class.php, BaseFormFilterDoctrine.class.phpは、後で削除するのでリネームの必要無いよ。
plugins/sfJobeetPlugin/lib/*/doctrine にあるbaseディレクトリを削除します。
$ rm -rf plugins/sfJobeetPlugin/lib/form/doctrine/base $ rm -rf plugins/sfJobeetPlugin/lib/filter/doctrine/base $ rm -rf plugins/sfJobeetPlugin/lib/model/doctrine/base
Subversion使っている場合は、svn delを使います。
$ svn del plugins/sfJobeetPlugin/lib/form/doctrine/base $ svn del plugins/sfJobeetPlugin/lib/filter/doctrine/base $ svn del plugins/sfJobeetPlugin/lib/model/doctrine/base
mv時に付いて来ちゃったsfJobeetPlugin内のsfDoctrineGuardPluginを削除します。
$ svn del plugins/sfJobeetPlugin/lib/form/doctrine/sfDoctrineGuardPlugin $ svn del plugins/sfJobeetPlugin/lib/filter/doctrine/sfDoctrineGuardPlugin $ svn del plugins/sfJobeetPlugin/lib/model/doctrine/sfDoctrineGuardPlugin
移動、リネーム、削除が完了したら、クラスをビルドし直します。
$ php symfony doctrine:build-forms $ php symfony doctrine:build-filters $ php symfony doctrine:build-models
最後のは、タイポ
$ php symfony doctrine:build-model
build-modelはsいりません。
modelの中身は、pluginのみになります。
lib/model `-- doctrine |-- sfDoctrineGuardPlugin | |-- base | | |-- BasesfGuardGroup.class.php | | |-- BasesfGuardGroupPermission.class.php | | |-- BasesfGuardPermission.class.php | | |-- BasesfGuardRememberKey.class.php | | |-- BasesfGuardUser.class.php | | |-- BasesfGuardUserGroup.class.php | | `-- BasesfGuardUserPermission.class.php | |-- sfGuardGroup.class.php | |-- sfGuardGroupPermission.class.php | |-- sfGuardGroupPermissionTable.class.php | |-- sfGuardGroupTable.class.php | |-- sfGuardPermission.class.php | |-- sfGuardPermissionTable.class.php | |-- sfGuardRememberKey.class.php | |-- sfGuardRememberKeyTable.class.php | |-- sfGuardUser.class.php | |-- sfGuardUserGroup.class.php | |-- sfGuardUserGroupTable.class.php | |-- sfGuardUserPermission.class.php | |-- sfGuardUserPermissionTable.class.php | `-- sfGuardUserTable.class.php `-- sfJobeetPlugin |-- JobeetAffiliate.class.php |-- JobeetAffiliateTable.class.php |-- JobeetCategory.class.php |-- JobeetCategoryAffiliate.class.php |-- JobeetCategoryAffiliateTable.class.php |-- JobeetCategoryTable.class.php |-- JobeetJob.class.php |-- JobeetJobTable.class.php `-- base |-- BaseJobeetAffiliate.class.php |-- BaseJobeetCategory.class.php |-- BaseJobeetCategoryAffiliate.class.php `-- BaseJobeetJob.class.php
いくつかの新しいディレクトりが、sfJobeetPluginからインクルードされたスキーマによって生成されたことに気がつくでしょう
このディレクトりは、schemaにより生成されたトップレベルのmoduleや基底クラスを含んでいます。
例えば、JobeetJobクラスはこのようなクラス構造を持っています。
Class Name | Extends | Path | Description |
---|---|---|---|
JobeetJob | PluginJobeetJob | lib/model/doctrine/sfJobeetPlugin/JobeetJob.class.php | PluginJobeetJobクラスを継承しています。現在のプロジェクト用にカスタマイズする場合はこのクラスを変更します。 |
PluginJobeetJob | BaseJobeetJob | plugins/sfJobeetPlugin/lib/model/doctrine/PluginJobeetJob.class.php | このクラスに変更を加えると、継承先全てのクラスに影響を及ぼします。バグフィックスとかは、こっちに |
BaseJobeetJob | sfDoctrineRecord | lib/model/doctrine/sfJobeetPlugin/base/BaseJobeetJob.class.php | doctrine:build-modelsを走らせる度に、schema.ymlを元に自動生成されます。 |
JobeetJobTable | PluginJobeetJobTable | lib/model/doctrine/sfJobeetPlugin/JobeetJobTable.class.php | JobeetJobクラスと同様に、Doctrine_Tableのインスタンスであることが期待されます。Doctrine::getTable('JobeetJob')で返されるのがこのクラスです。 |
PluginJobeetJobTable | Doctrine_Table | lib/model/doctrine/sfJobeetPlugin/JobeetJobTable.class.php | Doctrine_Tableクラスの全ての機能を有しています。 |
この生成された構造により、JobeetJobクラスを編集すればsfJobeetPluginのモデルを変更することができます。スキーマの編集、カラムの追加、リレーションの追加は、setTableDefinition()とsetUp()関数を上書きすることで可能です。
pluginフォルダ内に、formのbaseクラスが無いことを確認しましょう。これらのファイルは、プロジェクト全体で利用され、doctrine:build-formsと doctrine:build-filtersタスクにより自動生成されるものです。
pluginから、ファイルを削除します。
$ rm plugins/sfJobeetPlugin/lib/form/doctrine/BaseFormDoctrine.class.php $ rm plugins/sfJobeetPlugin/lib/filter/doctrine/BaseFormFilterDoctrine.class.php
symfony 1.2.0 もしくは 1.2.1を利用している人は、plugins/sfJobeetPlugin/lib/filter/base/ディレクトリにあります。
subversion利用している人は、svn delで削除して下さい。
Jobeet.class.phpも移動させましょう。
$ mv lib/Jobeet.class.php plugins/sfJobeetPlugin/lib/
移動させたら、キャッシュをクリアします。
$ php symfony cc
APCの様な、アクセラレーターを利用している方は、Apacheを再起動させてください。
全てのmodelファイルをpluginへ移動させたら、移動後も問題なく動くことを確認するためにテストをしましょう。
$ php symfony test:all
The Controllers and the Views
続いて、moduleもpluginへ移動させます。
$ mv apps/frontend/modules plugins/sfJobeetPlugin/
module名の衝突回避のために、module名の頭にplugin名を付ける習慣があります。
$ mv apps/frontend/modules/affiliate plugins/sfJobeetPlugin/modules/sfJobeetAffiliate $ mv apps/frontend/modules/api plugins/sfJobeetPlugin/modules/sfJobeetApi $ mv apps/frontend/modules/category plugins/sfJobeetPlugin/modules/sfJobeetCategory $ mv apps/frontend/modules/job plugins/sfJobeetPlugin/modules/sfJobeetJob $ mv apps/frontend/modules/language plugins/sfJobeetPlugin/modules/sfJobeetLanguage
mvしたから、frontend下にはmodules無いのでは?
以下、svn利用者向け。パスが長いので、cdします。
$ cd plugins/sfJobeetPlugin/modules $ svn mv affiliate sfJobeetAffiliate $ svn mv api sfJobeetApi $ svn mv category sfJobeetCategory $ svn mv job sfJobeetJob $ svn mv language sfJobeetLanguage $ cd -
module内のactions.class.phpとcomponents.class.phpに記載されているクラス名もリネームします。
include_partial()とinclude_component()のパスも変更します。
- sfJobeetAffiliate/templates/newSuccess.php
- sfJobeetAffiliate/templates/_form.php (change affiliate to sfJobeetAffiliate)
- sfJobeetCategory/templates/showSuccess.atom.php
- sfJobeetCategory/templates/showSuccess.php
- sfJobeetJob/templates/editSuccess.php
- sfJobeetJob/templates/indexSuccess.atom.php
- sfJobeetJob/templates/indexSuccess.php
- sfJobeetJob/templates/newSuccess.php
- sfJobeetJob/templates/searchSuccess.php
- sfJobeetJob/templates/showSuccess.php
- apps/frontend/templates/layout.php
(Job moduleの)searchとdeleteアクション中のjobをsfJobeetJobにリネームしましょう。
<?php // plugins/sfJobeetPlugin/modules/sfJobeetJob/actions/actions.class.php class sfJobeetJobActions extends sfActions { public function executeSearch(sfWebRequest $request) { if (!$query = $request->getParameter('query')) { return $this->forward('sfJobeetJob', 'index'); } $this->jobs = Doctrine::getTable('JobeetJob')->getForLuceneQuery($query); if ($request->isXmlHttpRequest()) { if ('*' == $query || !$this->jobs) { return $this->renderText('No results.'); } else { return $this->renderPartial('sfJobeetJob/list', array('jobs' => $this->jobs)); } } } public function executeDelete(sfWebRequest $request) { $request->checkCSRFProtection(); $jobeet_job = $this->getRoute()->getObject(); $jobeet_job->delete(); $this->redirect('sfJobeetJob/index'); } // ... }
最後に、routing.ymlファイルも修正します。
# apps/frontend/config/routing.yml affiliate: class: sfDoctrineRouteCollection options: model: JobeetAffiliate actions: [new, create] object_actions: { wait: GET } prefix_path: /:sf_culture/affiliate module: sfJobeetAffiliate api_jobs: url: /api/:token/jobs.:sf_format class: sfDoctrineRoute param: { module: sfJobeetApi, action: list } options: { model: JobeetJob, type: list, method: getForToken } requirements: sf_format: (?:xml|json|yaml) category: url: /:sf_culture/category/:slug.:sf_format class: sfDoctrineRoute param: { module: sfJobeetCategory, action: show, sf_format: html } options: { model: JobeetCategory, type: object, method: doSelectForSlug } requirements: sf_format: (?:html|atom) job_search: url: /:sf_culture/search.:sf_format param: { module: sfJobeetJob, action: search, sf_format: html } requirements: sf_format: (?:html|js) job: class: sfDoctrineRouteCollection options: model: JobeetJob column: token object_actions: { publish: PUT, extend: PUT } prefix_path: /:sf_culture/job module: sfJobeetJob requirements: token: \w+ job_show_user: url: /:sf_culture/job/:company_slug/:location_slug/:id/:position_slug class: sfDoctrineRoute options: { model: JobeetJob, type: object, method_for_query: retrieveActiveJob } param: { module: sfJobeetJob, action: show } requirements: id: \d+ sf_method: GET change_language: url: /change_language param: { module: sfJobeetLanguage, action: changeLanguage } localized_homepage: url: /:sf_culture/ param: { module: sfJobeetJob, action: index } requirements: sf_culture: (?:fr|en) homepage: url: / param: { module: sfJobeetJob, action: index }
もし、Jobeetのウェブサイトをブラウザで閲覧しようとした場合、moduleが利用できませんという例外が返ってくるでしょう。プロジェクト内の全てのアプリ間で共有されるので、settings.ymlで明示的に利用を宣言しなければなりません。
// apps/frontend/config/settings.yml all: .settings: enabled_modules: - default - sfJobeetAffiliate - sfJobeetApi - sfJobeetCategory - sfJobeetJob - sfJobeetLanguage
最後のステップは、functional testsをします。
Plugin Activation
pluginは、ProjectConfigurationクラスで利用可能にしなければなりません。
デフォルトのブラックリスト形式の場合は、変更する必要はありません。
<?php // config/ProjectConfiguration.class.php public function setup() { // 基本全部利用可能で、引数で示すpluginのみ利用不可 // 僕は、sfDoctrinePluginを使っているので、sfPropelPluginが不可になってます $this->enableAllPluginsExcept(array('sfDoctrinePlugin', 'sfCompat10Plugin')); }
古いsymfonyの場合は、変更を加える必要があります。しかし、enablePlugins()関数を用いた、このホワイトリスト形式はよい方法です。
<?php // config/ProjectConfiguration.class.php public function setup() { $this->enablePlugins(array('sfDoctrinePlugin', 'sfGuardPlugin', 'sfFormExtraPlugin', 'sfJobeetPlugin')); }
The Tasks
タスクをpluginに移動させるのは、非常に簡単です。
$ mv lib/task plugins/sfJobeetPlugin/lib/
The Routing
pluginはroutingファイルも内包しています
$ mv apps/frontend/config/routing.yml plugins/sfJobeetPlugin/config/
The Assets
多少わかりにくくても、pluginはimages, stylesheetsそしてJavaScriptsファイルを含むことができます。Jobeet pluginを分散させたくないと思うとき、本当に理解できませんが、それはplugins/sfJobeetPlugin/web/ディレクトリを作成することによって、可能です。
plugin:publish-assetsタスクは、webディレクトリから、pluginのwebディレクトリへシンボリックリンクを張ります。これにより、ブラウザからpluginのwebディレクトリへのアクセスが可能となります。
非推奨なのかな?
$ php symfony plugin:publish-assets
The User
jobのhistoryに関する関数を移動させる必要があります。JobeetUserクラスを作ってmyUserクラスに継承させることが可能です。しかし、もっといい方法があります。特に、いくつかのpluginがクラスに新しい関数を追加したい場合に。
symfonyのコアオブジェクトは、イベントを通知します。今回のケースでは、sfUserオブジェクトで未定義のメソッドが呼ばれた場合に起こるuser.method_not_foundイベントを取得する必要があります。
symfonyが初期化させたとき、plugin configurationクラスを持つ全てのpluginも初期化されます。
<?php // plugins/sfJobeetPlugin/config/sfJobeetPluginConfiguration.class.php class sfJobeetPluginConfiguration extends sfPluginConfiguration { public function initialize() { $this->dispatcher->connect('user.method_not_found', array('JobeetUser', 'methodNotFound')); } }
イベントは、sfEventDispatcherオブジェクトにより管理されます。登録は、シンプルでconnect()メソッドを呼ぶだけです。connect()メソッドは、イベント名とPHP callableを関連付けます。
PHP callableは、PHPの変数でcall_user_func()関数を利用できるように変換されます。そして、is_callable()関数に伝搬したときにtrueを返します。文字列は関数に、配列はオブジェクトもしくはクラスのメソッドに相当します。
上記コードにより、myUserオブジェクトはメソッドが見つからないときはいつも、JobeetUserクラスの静的関数であるmethodNotFound()を呼び出します。
myUserクラスの全てのメソッドを削除して、JobeetUserクラスを作成します。
<?php // apps/frontend/lib/myUser.class.php class myUser extends sfBasicSecurityUser { }
// plugins/sfJobeetPlugin/lib/JobeetUser.class.php class JobeetUser { static public function methodNotFound(sfEvent $event) { if (method_exists('JobeetUser', $event['method'])) { $event->setReturnValue(call_user_func_array( array('JobeetUser', $event['method']), array_merge(array($event->getSubject()), $event['arguments']) )); return true; } } static public function isFirstRequest(sfUser $user, $boolean = null) { if (is_null($boolean)) { return $user->getAttribute('first_request', true); } else { $user->setAttribute('first_request', $boolean); } } static public function addJobToHistory(sfUser $user, JobeetJob $job) { $ids = $user->getAttribute('job_history', array()); if (!in_array($job->getId(), $ids)) { array_unshift($ids, $job->getId()); $user->setAttribute('job_history', array_slice($ids, 0, 3)); } } static public function getJobHistory(sfUser $user) { // $ids = $this->getAttribute('job_history', array()); thisではなくuser $ids = $user->getAttribute('job_history', array()); if (!empty($ids)) { return Doctrine::getTable('JobeetJob') ->createQuery('a') ->whereIn('a.id', $ids) ->execute(); } else { return array(); } } static public function resetJobHistory(sfUser $user) { $user->getAttributeHolder()->remove('job_history'); } }
ディスパッチャがmethodNotFound()メソッドを呼ぶと、sfEventオブジェクトに通知されます。
methodNotFound()メソッドがJobeetUserクラスに存在する場合、呼び出された後に通知を返します。もし、存在しない場合はsymfonyは次のイベントリスナーを呼び出すか、例外を投げます。
getSubject()メソッドは、イベント(この場合のイベントは現在のmyUserオブジェクト)の通知を返します。
新たなクラスを作成した場合は、ブラウジングやテストの前にキャッシュをクリアするのを忘れないでください。
$ php symfony cc
Using Plugins
あなたが新機能を実行し始めるもしくは、古典的なウェブ問題を解決しようとするなら、だれかが既に同じ問題を解決して、symfony pluginとして解決策をパッケージしている可能性があります。公式pluginを探すなら、plugin sectionを訪れてみてください。
pluginは、インストールするための様々な方法を内包しています。
- plugin:installタスクを用いる (制作者がpluginをパッケージ化していて、かつsymfonyのウェブサイトにアップロードしてある場合に限り実行可能です。)
- パッケージをダウンロードして、手動でpluginディレクトリ以下に解凍する(この方法もまた、制作者がパッケージをアップロードしている必要があります。)
- pluginをsvn:extarnals(外部定義)する (制作者がpluginをsubversionでホストしているだけで、定義可能です。)
後ろ二つの方法は、簡単ですが柔軟性に欠けます。最初の方法は、symfonyのバージョンにあった最新版をインストールすることが可能で、アップグレードも容易です。さらに、pluginの依存関係解消も容易です。
Contributing a Plugin
Packaging a Plugin
pluginをパッケージ化するためにいくつかの必須ファイルを加える必要があります。始めに、READMEファイルをpluginのルートディレクトリに作成します。そして、インストール方法、何を提供するのか等々の説明を書き込みます。READMEファイルはMarkdown formatに従う必要があります。このファイルは、symfonyのウェブサイトで利用可能な多くのドキュメントの一つです。symfony plugin dingusを用いれば、READMEファイルをHTMLに変換してテストすることもできます。
Plugin Development Tasks
private, publicなpluginを作成する場合は、sfTaskExtraPluginのタスクを利用するといいでしょう。このpluginは主要チームにより保守されており、あなたのplugin作成の助けとなるでしょう。
- generate:plugin
- plugin:package
LICENSEファイルも作る必要があります。ライセンスを選ぶのは容易ではないでしょうが、symfonyのpluginは、symfonyと酷似したライセンス(MIT, BSD, LGPL, and PHP)のpluginのみをリストアップしています。pluginは、そのライセンスに従って公開されます。
最後のステップは、package.xmlをpluginのルートディレクトリに作成します。このファイルは、PEAR package syntaxに従います。
package.xmlは、以下に示すようにいくつかの部分からなります。
<!-- plugins/sfJobeetPlugin/package.xml --> <?xml version="1.0" encoding="UTF-8"?> <package packagerversion="1.4.1" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd" > <name>sfJobeetPlugin</name> <channel>plugins.symfony-project.org</channel> <summary>A job board plugin.</summary> <description>A job board plugin.</description> <lead> <name>Fabien POTENCIER</name> <user>fabpot</user> <email>fabien.potencier@symfony-project.com</email> <active>yes</active> </lead> <date>2008-12-20</date> <version> <release>1.0.0</release> <api>1.0.0</api> </version> <stability> <release>stable</release> <api>stable</api> </stability> <license uri="http://www.symfony-project.com/license"> MIT license </license> <notes /> <contents> <!-- CONTENT --> </contents> <dependencies> <!-- DEPENDENCIES --> </dependencies> <phprelease> </phprelease> <changelog> <!-- CHANGELOG --> </changelog> </package>
contentタグは、packageに含まれるファイル情報を含みます。
<contents> <dir name="/"> <file role="data" name="README" /> <file role="data" name="LICENSE" /> <dir name="config"> <file role="data" name="config.php" /> <file role="data" name="schema.yml" /> </dir> <!-- ... --> </dir> </contents>
dependenciesタグは、pluginの依存関係(PHP, symfonyのバージョンや他のpluginが必要であるなど)を含みます。この情報は、plugin:installタスクで利用され、現在の環境に最適なpluginがインストールされます。必要ならば、依存関係を考慮して他のpluginもインストールされます。
<dependencies> <required> <php> <min>5.0.0</min> </php> <pearinstaller> <min>1.4.1</min> </pearinstaller> <package> <name>symfony</name> <channel>pear.symfony-project.com</channel> <min>1.2.0</min> <max>1.3.0</max> <exclude>1.3.0</exclude> </package> </required> </dependencies>
ここに示すように、symfonyに依存関係を明示しなければなりません。インストール可能なsymfonyの最低と最高のバージョン情報や依存関係にあるplugin情報を含めることができます。
<package> <name>sfFooPlugin</name> <channel>plugins.symfony-project.org</channel> <min>1.0.0</min> <max>1.2.0</max> <exclude>1.2.0</exclude> </package>
changelogタグは含めなくても構いませんが、リリースされるまでの変更という有益な情報を提供できます。この情報は、Changelogタブやplugin feedで提供が可能です。
<changelog> <release> <version> <release>1.0.0</release> <api>1.0.0</api> </version> <stability> <release>stable</release> <api>stable</api> </stability> <license uri="http://www.symfony-project.com/license"> MIT license </license> <date>2008-12-20</date> <license>MIT</license> <notes> * fabien: First release of the plugin </notes> </release> </changelog>
Hosting a Plugin on the symfony Website
もし、pluginを作成してコミュニティで共有したいなら、アカウントを作成しましょう。既にアカウントを所持している場合は、new pluginページでpluginの登録を行います。
pluginの管理者になると、自動的にadminタブでplugin管理に必要な情報を得ることができます。