ここの情報は古いです。ご理解頂いた上でお取り扱いください。

source: OpenPNE3/doc/branches/3.0/plugins-tutorial/ja/create_plugin.rd @ 9769

Last change on this file since 9769 was 9769, checked in by kiwa, 14 years ago

doc: Added content in create_plugin.rd

  • Property svn:mime-type set to application/octet-stream
File size: 19.9 KB
Line 
1=begin
2= OpenPNE3プラグインの作り方
3
4== index
5* ((<"はじめに">))
6* ((<"前提条件">))
7* ((<"プラグインの骨組みの作成">))
8  * ((<"OpenPNE3のディレクトリに移動">))
9  * ((<"タスクの実行">))
10      * ((<"補足:プラグインの命名規則について">))
11  * ((<"モジュールの追加">))
12* ((<"表示の変更">))
13  * ((<"アクションの編集">))
14  * ((<"テンプレートの編集">))
15  * ((<"認証の有無の変更">))
16* ((<"データベースモデルの作成">))
17* ((<"パーツの追加">))
18  * ((<"パーシャルの追加">))
19  * ((<"レイアウト設定の作成">))
20* ((<"フォームの作成">))
21  * ((<"フォームの編集">))
22        * ((<"MemberNewsForm.class.php">))
23  * ((<"モデルの操作">))
24        * ((<"_sampleParts.php">))
25      * ((<"include_box($id, $title = ”, $body = ”, $option = array()) の説明">))
26* ((<"アクションの編集">))
27        * ((<"actions.class.php">))
28* ((<"プロフィール画面での確認機能の作成">))
29        * ((<"_sampleParts2.php">))
30  * ((<"レイアウト設定の変更">))
31        * ((<"view.yml">))
32
33== はじめに
34
35OpenPNE3はあらゆる機能をプラグインとして追加することができます。
36OpenPNE3はsymfonyフレームワークを利用していますが、OpenPNE3のプラグインはsymfonyのプラグインとは違ったプラグインの構造を持っています。
37このドキュメントでは、OpenPNE3のプラグインの作成方法を紹介します。
38
39
40
41== 前提条件
42
43このドキュメントは、以下の条件が揃っていることを前提とします。
44
45* OpenPNE3がインストール・動作する環境がある
46* 上の環境においてコンソールでの作業が行える
47
48
49
50== プラグインの骨組みの作成
51
52OpenPNE3は、プラグインの骨組みを作成するためのタスクも用意しています。
53プラグインの作成は、そのタスクを利用して骨組みを作成します。
54
55
56=== OpenPNE3のディレクトリに移動
57
58コンソールでOpenPNE3がインストールされたディレクトリに移動します。
59
60((*以下、「/var/www/OpenPNE3」にOpenPNE3をインストールした想定で説明します。*))
61
62((%$ cd /var/www/OpenPNE3%))
63
64
65=== タスクの実行
66
67次に、プラグイン作成タスクを実行します。例として「opSamplePlugin」という名前のプラグインを作成する場合を挙げます。
68
69以下のタスクを実行することにより、OpenPNE3の「plugins」ディレクトリ下に「opSamplePlugin」が追加されます。
70
71((%$ symfony opGenerate:plugin ((*opSamplePlugin*))%))
72
73新しく追加された「opSamplePlugin」ディレクトリの中には、4つの空のディレクトリが作られます。
74
75 apps
76 conf
77 i18n
78 lib
79
80
81+ 補足:プラグインの命名規則について
82
83現状ではプラグイン名の命名規則は未定ですが、
84
85((*「opHogehogePlugin」*))
86
87という方向で考えています。
88
89
90=== モジュールの追加
91
92symfonyプラグインとの大きな違いは、「apps」ディレクトリを配置できることにあります。
93この下に、アプリケーションごとのモジュールを配置することができます。
94また、これらの作成を自動的に行うためのタスクも用意されています。
95
96例として、PCからのSNSメンバーが利用するpc_frontendアプリケーションに「hello」モジュールを追加する場合を挙げます。
97以下のタスクで「apps」ディレクトリ下に空の「modules」ディレクトリが含まれた「pc_frontend」ディレクトリが作成されます。
98
99((%$ symfony opGenerate:app ((*opSamplePlugin pc_frontend*))%))
100
101さらに、「pc_frontend」に「hello」モジュールを追加します。
102以下のタスクで「pc_frontend/modules」ディレクトリ内に「hello」ディレクトリが作成されます。
103
104((%$ symfony opGenerate:module ((*opSamplePlugin pc_frontend hello*))%))
105
106http://sns.example/
107
108がOpenPNE3のURLであったとき、下記のURLにアクセスして((*「Module "hello" created」*))というページが表示されたら骨組みの完成です。
109
110http://sns.example/hello
111
112
113
114== 表示の変更
115
116=== アクションの編集
117
118「plugins/opSamplePlugin/app/pc_frontend/modules/hello」下には 「actions」と「templates」の2つのディレクトリが作成されます。
119「actions」ディレクトリの中には、最初から「actions.class.php」が用意されています。
120中身はこのようになっています。
121
122 …(省略)…
123 class helloActions extends sfActions
124   {
125   /**
126   * Executes index action
127   *
128   * @param sfRequest $request A request object
129   */
130   public function executeIndex($request)
131   {
132     $this->forward(’default’, ‘module’);
133   }
134 }
135
136 $this->forword('default','module');
137
138となっているため、「Module “hello” created」のページにフォワードしています。ここを
139
140 return sfView::SUCCESS;
141
142に置き換えてみます。
143
144 …(省略)…
145 class helloActions extends sfActions
146   {
147   /**
148   * Executes index action
149   *
150   * @param sfRequest $request A request object
151   */
152   public function executeIndex($request)
153   {
154    return sfView::SUCCESS;
155   }
156 }
157
158
159=== テンプレートの編集
160
161次に、テンプレートを編集します。「templates」ディレクトリには、最初から「indexSuccess.php」が用意されています。
162executeIndex() で sfView::SUCCESS が返されるとこのテンプレートを表示します。中身は空白のファイルなので、適当な編集を行います。例として「Hello world!」と入力した場合を挙げます。
163
164http://sns.example/hello
165
166にアクセスすると、OpenPNEのロゴと「Hello world!」の文章が表示されます。
167
168
169=== 認証の有無の変更
170この状態の「hello」モジュールは、ログインしていなくても表示させることができます。
171ログイン認証を利用するために、「hello」ディレクトリの中に、新しく「config」ディレクトリを作成して「security.yml」というファイルを作成し、以下のような内容にします。
172
173 all:
174   is_secure: on
175   credentials: SNSMember
176
177YAMLなので、インデントにはタブでなくて半角スペース2を使用します。
178((*その後、 ((%symfony cc%)) でキャッシュを削除してください。*))
179
180そうすると、ログインした状態でないと
181
182http://sns.example/hello
183
184にアクセスできなくなります。ログインしてアクセスすると、ログイン後のメニューが付いたページになります。
185
186
187
188== データベースモデルの作成
189
190プラグイン独自のデータベースモデルを作成する方法です。
191例として、((<MyNews|URL:http://trac.openpne.jp/wiki/pne-customize#MyNews%E6%A9%9F%E8%83%BD%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B>))を作成する場合を挙げます。以降、MyNewsの例で進めていきます。
192
193プラグイン用のデータベースモデルの作成法はsymfonyのマニュアルにある通りです。
194
195((<URL:http://www.symfony-project.org/book/1_2/17-Extending-Symfony#Plug-In%20File%20Structure>))(英語)
196
197プラグインディレクトリの直下にある「config」ディレクトリ内に「schema.yml」を作成します。
198MyNewsを作る上で、必要なフィールドは以下の通りです。
199
200:ID
201   1対1のモデルにしてもよいのですが、今回はこのテーブルのための固有のキーを割り振ることにします。
202:メンバーID
203   コアにあるmemberモデルの外部キーです
204:本文
205   
206:更新日時
207   
208
209このモデルを作成するために、「schema.yml」を次のように編集します。
210
211 propel:
212   _attributes: { package: plugins.opSamplePlugin.lib.model }
213 
214   member_news:
215     id: ~
216     member_id : { type: integer, foreignTable: member, foreignReference: id }
217     content:    { type: longvarchar }
218     updated_at: ~
219
220「security.yml」同様、YAML はタブ文字ではなくスペース2文字でインデントするということに気を付けてください。
221
222id と指定したフィールドに関しては、特に何もオプションを指定しないと自動的にプライマリーキーとなり、オートインクリメントが有効になります。
223
224●●●_id とやることにより、●●●テーブルの外部キーになります。同じ「schema.yml」ファイル上にそのテーブルがあれば、自動的にそのテーブルの外部キーになりますが、memberテーブルの宣言は別の場所にあるので((*しっかりと foreignTableを指定します。*))
225
226((*※ アルファ版の段階でコアのモデルを利用するときは、モデルの変更が行われることがありますのでご注意ください。*))
227
228updated_atは更新時に自動的に更新時時刻が登録されるフィールドになります。
229このファイルを保存した後、
230
231((%$ symfony openpne:install%))
232
233コマンドを利用して、データベースモデルを再構築します。
234
235((*※ 将来的には、OpenPNE3のすべてのデータベースモデルを初期化しないで新しく作成したモデルを追加することができるようになる予定です。*))
236
237
238
239== パーツの追加
240
241OpenPNE2のカスタマイズは、特定ページ(例えばpage_h_home)に新しい機能を加えるとき、
242そのページのアクションを編集し、さらにテンプレートを編集し……、といった作業が必要でした。
243OpenPNE3は、プラグインを追加するだけで特定ページに、新たな部品を追加することができます。
244
245この仕組みをテンプレート拡張と呼んでいます。
246
247OpenPNE3のテンプレートでは、複数のテンプレート部品(パーツ)によって構成される仕組みになっています。
248パーツにはIDを持っていて、その前後に別のパーツを挿入することが可能です。
249
250「My News!機能」を実装するためにはホームとプロフィールに新しく部品を挿入する必要があります。
251
252informationの下に、新たに「My News!」のフォームを挿入します。まずはinformationの下に文字を表示できるようにしてみます。
253
254
255=== パーシャルの追加
256
257まずは、新たに挿入するテンプレートを追加します。
258
259((*opSamplePlugin/apps/pc_frontend/modules/hello/templates*))
260
261に新たに ((*_sampleParts.php*))を追加します。これは、informationの下に表示するパーシャルです。
262
263symfonyのパーシャルについてはこちらをご覧ください。
264
265((<URL:http://www.symfony-project.org/book/1_2/07-Inside-the-View-Layer#Templating>))(英語)
266
267_samplePlarts.phpには「Hello world!!」と入力します。
268
269
270=== レイアウト設定の作成
271
272OpenPNE3のホームである、member/home に上に今回作成したテンプレートを挿入するため、
273
274((*opSamplePlugin/apps/pc_frontend/modules*))
275
276に、新たに((*member*)) ディレクトリ。さらにその中に ((*config*)) ディレクトリを作成します。
277((*config*)) ディレクトリに、 ((*view.yml*)) ファイルを作成して以下のように編集します。
278
279 homeSuccess:
280   customize:
281     sampleParts:
282       template: [hello, sampleParts]
283       parts: [information]
284       target: [after]
285
286:homeSuccess
287   memberモジュールで、homeSuccessテンプレート(homeアクションが成功したときに呼び出されるテンプレート)の設定をここで追加しています
288:customize
289   テンプレート拡張を実現します
290:sampleParts
291   テンプレート名です
292:template
293   特定のパーシャルを指定します
294:parts
295   パーツのidを指定します
296:target
297   partsで指定したidのどこに配置するかを定めます
298
299これにより、homeSuccess の information の後に hello/sampleParts が挿入されるようになります。
300
301設定ファイルを追加、編集した後には必ず、以下のコマンドでキャッシュを削除してください。
302
303((%$ symfony cc%))
304
305ホームにアクセスすると、informationの下に「Hello world!!」の文字が表示されるようになっています。
306
307
308
309== フォームの作成
310
311=== フォームの編集
312
313((*opSamplePlugin/lib/form*)) にはあらかじめ、((*MemberNewsForm.class.php*))が存在します。
314これはモデルの構築時に自動的に作成されるクラスで、何も加工せずに利用するとすべてのフィールドが編集できるフォームを提供しています。
315(id , member_id, content, update_at フィールドが編集できるフォーム)
316
317MyNews!機能で編集可能な項目は content フィールドだけなので、そのように対応させるため、以下のように編集します。
318
319++ MemberNewsForm.class.php
320 <?php
321 
322 (コメント行省略)
323 class MemberNewsForm extends BaseMemberNewsForm
324 {
325   public function configure()
326   {
327     $this->setWidgets(array(
328       ’content’ => new sfWidgetFormTextarea()
329     ));
330
331     $this->setValidators(array(
332       ’member_id’ => new sfValidatorPropelChoice(array(’model’ => ‘Member’, ‘column’ => ‘id’)),
333       ’content’ => new sfValidatorString(array(’required’ => false))
334     ));
335 
336     $this->widgetSchema->setNameFormat(’member_news[%s]‘);
337   }
338 }
339
340フォームの作成法については以下を参考にしてください。
341
342:The symfony Forms Book - 第1章 - フォームの作成
343   ((<URL:http://www.symfony-project.org/book/forms/1_2/ja/01-Form-Creation>))
344:The symfony Forms Book - 第4章 - Propelとの統合(symfony1.1時点)
345   ((<URL:http://symfony.xrea.jp/1.1/forms_book/04-Propel-Integration.html>))
346
347
348=== モデルの操作
349
350さらに、このフォームをパーシャルに挿入します。
351((*opSamplePlugin/apps/pc_frontend/modules/hello/templates/_sampleParts.php*)) を以下のように変更します。
352
353++ _sampleParts.php
354 <?php
355 $criteria = new Criteria();
356 $criteria->add(MemberNewsPeer::MEMBER_ID,$sf_user->getMember()->getId());
357 $memberNews = MemberNewsPeer::doSelectOne($criteria);
358 
359 $form = new MemberNewsForm($memberNews);
360 
361 include_box(’MyNews’,'MyNews’,”,array(’form’=>$form,’url’=>’hello/updateNews’));
362
363モデルの操作についてはこちらを参考にしてください。
364:The Definitive Guide to symfony - 第8章 - モデルレイヤーの内側(symfony1.1時点)
365   ((<URL:http://symfony.xrea.jp/1.1/book/08-Inside-the-Model-Layer.html>))
366
367このコードでは、先ほど編集したフォームのインスタンスを作成しています。
368コンストラクタにモデルのインスタンスを渡すことにより、現在DBに登録されている内容がデフォルト値として設定されます。
369フォームを出力するときには、OpenPNE3用パーツを挿入するための PartsHelper(最初からロードされています)
370に含まれている、include_box() を利用しています。
371
372+ include_box($id, $title = ”, $body = ”, $option = array()) の説明
373
374:$id
375   このパーツのIDです。同一ページで同じIDを利用しないように注意してください。
376:$title
377   このパーツのタイトル部に表示させる文字列です。
378:$body
379   このパーツの内容です。MyNews!機能の場合はフォームを表示させるので空白です。
380:$option
381   パーツのオプションです
382   :form
383      フォームを使用する場合に必要なパラメータです。formを渡すときはこのパラメータにフォームのインスタンスを渡します。
384   :url
385      formがsubmitされたときのアクション先を指定します
386
387編集後、更新するとOpenPNEのホームにMyNews!の編集フォームが表示されるようになっています。
388
389
390
391== アクションの編集
392
393((*plugins/opSamplePlugin/apps/pc_frontend/modules/hello/actions/actions.class.php*)) に、MyNewsが投稿されたときのアクションを記します。
394
395「モデルの操作」で、ポスト先のアクション名は ((*updateNews*)) としたので、
396このファイルで宣言している helloAction クラスに新たなメソッド「((*executeUpdateNews*))」を追加します。
397メソッド名は((*executeアクション名()*))(アクション名の最初は大文字)という規則です。
398
399++ actions.class.php
400 <?php
401 // (コメント行省略)..
402 
403 class helloActions extends sfActions
404 {
405   // (コメント行省略)..
406   public function executeIndex($request)
407   {
408     return sfView::SUCCESS;
409   }
410 
411   public function executeUpdateNews($request)
412   {
413     // POSTリクエストかどうかを確認する
414     if ($request->isMethod(sfRequest::POST))
415     {
416       // member_news から 自分のメンバーIDが一致する1行を取りだす
417       $criteria = new Criteria();
418       $criteria->add(MemberNewsPeer::MEMBER_ID,$this->getUser()->getMember()->getId());
419       $memberNews = MemberNewsPeer::doSelectOne($criteria);
420 
421       // 前回作成した memberNewsFormの初期値として先ほど取りだした1行をセットする
422       $memberNewsForm = new MemberNewsForm($memberNews);
423 
424       // POSTされたパラメータを取得する
425       $param = $request->getParameter(’member_news’);
426       $param['member_id'] = $this->getUser()->getMember()->getId();
427 
428       // パラメータをバインドする
429       $memberNewsForm->bind($param);
430 
431       // 入力された値が妥当かどうかを確かめる
432       if ($memberNewsForm->isValid())
433       {
434         // データベースに保存
435         $memberNewsForm->save();
436       }
437     }
438     // 最後に自分のホームにリダイレクトする
439     return $this->redirect(’@homepage’);
440   }
441 }
442
443アクションでは、((*$this->getUser()->getMemer()*))で自分のメンバー情報が取得できます。
444これは自分の情報がセットされたクラス Member のインスタンスです。また、テンプレートでは $sf_user で $this->getUser() が取得できます。
445よって、 $sf_user->getMember() で自分のメンバー情報が取得できます。
446
447
448== プロフィール画面での確認機能の作成
449
450((*plugins/opSamplePlugin/apps/pc_frontend/modules/hello/templates*))
451
452にパーシャル ((*_sampleParts2.php*)) を追加します。これでMyNewsを表示できるよう、以下のような編集をおこないます。
453
454++ _sampleParts2.php
455 <?php
456 // idパラメータ(プロフィールページを表示するとき指定しているメンバーID)
457 // を取得します。自己プロフィールのように id がない場合は、自分のメンバーIDを $memberIdに代入する
458 $memberId = $sf_request->getParameter(’id’, $sf_user->getMember()->getId());
459 
460 // member_news テーブルから取得した $memberIdと一致する1行を取り出す
461 $criteria = new Criteria();
462 $criteria->add(MemberNewsPeer::MEMBER_ID, $memberId);
463 $memberNews = MemberNewsPeer::doSelectOne($criteria);
464 
465 $body = “”;
466 // もし行が存在した場合は、contentフィールドの内容を$bodyに代入する
467 if ($memberNews)
468 {
469   $body = $memberNews->getContent();
470 }
471 
472 // Partsヘルパー(OpenPNE3独自のヘルパー)に含まれる
473 // include_box関数を使って $body を出力する
474 // include_boxの仕様は前回の記事で説明
475 include_box(’MyNews’,'MyNews’,nl2br($body));
476
477
478=== レイアウト設定の変更
479
480templateに sampleParts2 を指定します。
481
482((*plugins/opSamplePlugin/apps/pc_frontend/modules/member/config/view.yml*))を以下のようにします。
483
484++ view.yml
485 homeSuccess:
486 …(省略)…
487       target: [after]
488 
489 profileSuccess:
490   customize:
491     sampleParts2:
492       template: [hello, sampleParts2]
493       parts: [profile]
494       target: [before]
495
496設定ファイル編集後、 ((%((*symfony cc*))%)) でキャッシュ削除をします。
497これでプロフィール画面にMyNewsの内容が表示されます。
498
499
500これでMyNews!機能は完成です。
501
502=end
Note: See TracBrowser for help on using the repository browser.