ExtJSアプリケーションアーキテクチャ:Zend Frameworkアプローチ

ExtJSベースのRIAアプリケーションアーキテクチャに関する奇妙な記事に加えて、この問題に対する独自の代替アプローチを提供したいと思います。 これは、JavaScriptで記述されたZendFrameworkのようなxFrameフレームワークを使用することにあります。 カットの下-システムの主要な要素の説明、デモアプリケーションとソースコードへのリンク。



xFrameの歴史は単一の注文から始まりました。 クライアントは、自分のWebサイトに財務表示システムを実装することを望んでいました。 レポート。 彼はすでにExtJSに精通しており(サイト管理パネルが実装されています)、ライブラリが好きで、ExtJSグリッドの形式でレポートを表示したいと考えていました。 システムの追加要件は、さまざまなユーザーグループのレポートを表示するためのアクセス権の制限でした。 したがって、リソースへのアクセスの認証と配布を行うRIAアプリケーションを実装するタスクに直面しました。



サイトの管理パネルはそのような機能をサポートしていましたが、クライアントに適さないWebDesktopの形式で作成されました。 そのため、システムの開発をゼロから始めました。 当時、私はK. Zervasの本「Web 2.0:PHPでアプリケーションを作成する」を読んでいて、そこに記述されているZend Frameworkの精神に触発されました。 そして、ZFとまったく同じようなものを作成したかったのです。 そして、私はそれをやった。 基本的な機能は2日以内に実装され、デバッグには数日かかりました。 その後、報告システム自体の実装後、自由時間にフレームワークを提示可能な状態にし、一般に提出することにしました。



「コード」名xFrame (eXtjs FRAMEwork)と呼ぶ限り、フレームワークの最終的な名前はまだ思いつきません。 xFrameの実装:







xFrameのモデルは、Ext.data.Recordに基づいて実装されます。 モデルのクラス(コンストラクター)は、Ext.data.Record.create([])メソッドを使用して作成されます。 モデルに追加のメソッドをカプセル化する必要がある場合、 Ext.override()が使用されます。

Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  1. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  2. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  3. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  4. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  5. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  6. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  7. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  8. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  9. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  10. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  11. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  12. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  13. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  14. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  15. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



  16. Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .



Application.models.News = Ext.data.Record.create([ {name: 'Id' , type: 'int' }, {name: 'Permalink' , type: 'string' }, {name: 'Title' , type: 'string' }, {name: 'Brief' , type: 'string' }, {name: 'Text' , type: 'string' }, {name: 'DateCreated' , type: 'date' , dateFormat: 'Ym-d' }, ]); Ext. override (Application.models.News, { getLink : function () { return App.route({ permalink : this .get( "Permalink" ) }, "news" ); }, getDateCreated : function () { return this .get( "DateCreated" ).format( 'm/d/Y' ); } }); * This source code was highlighted with Source Code Highlighter .





また、各モデルについて、アプリケーションは自動的に2つの「静的」(インスタンスからではなく、コンストラクターから呼び出される)メソッドcreateStore(add_cfg) (モデルフィールドを使用してデータストアの構成オブジェクトを作成)およびcreateOne(ハッシュ) (モデルのインスタンスを作成し、ハッシュオブジェクトからフィールドに読み込みます)。



コントローラは 、ZFとの類推によって実装されます。 コントローラーを作成するには、クラス<controller_name> Controllerを作成して、アクション<action_name> Actionメソッドを作成する必要があります。 3つのパラメーターがアクションハンドラーに渡されます。アクションに渡されるパラメーターを持つハッシュ、アプリケーションオブジェクトへのリンク、ViewPortオブジェクトへのリンク。





  1. Application.controllers.FrontController = Ext.extend(Application.controllers.Abstract、{
  2. .................................................. .................................................. ...................
  3. newsAction: functionparams 、app、panel){
  4. panel.add({
  5. xtype: 'Application.components.NewsViewer'
  6. newsPermalink: params .permalink
  7. });
  8. }、
*このソースコードは、 ソースコードハイライターで強調表示されました。




プレゼンテーション機能は完全にExtJSコンポーネントに実装されています。 アプリケーションが初期化されると、ビューポートが作成され、ページ上の指定された場所にレンダリングされます。 コントローラー/アクションを変更すると、出力領域が変わります。 他のすべてのコンテンツは変更されません。 アクションメソッドを呼び出す前に、コンポーネントに関する出力領域がクリアされ、アクション自体がそれに必要なコンポーネントを追加できます。その後、アプリケーションはビューポートを再描画します。



システムの構造レベルでは、次の主要コンポーネントが区別されます。



Applicationクラスは、 アプリケーションの基盤です。 このクラスでは、システムの他のすべてのコンポーネントがカプセル化されます。





一般的に使用される方法:







アプリケーションを作成するとき、このクラスを継承し、必要な初期化メソッドを事前定義する必要があります。







  1. var App = new (Ext.extend(Application、{
  2. renderTo: 'app'
  3. autoRun: true
  4. initAcl: function (){
  5. this .constructor.superclass.initAcl.call( this );
  6. this .acl.addRole( new Application.Acl.Role(....................));
  7. .................................................. ....................
  8. }、
  9. initRouter: function (){
  10. this .constructor.superclass.initRouter.call( this );
  11. この .router.addRoute( 新しい Application.Router.Route(....................................} ));
  12. }
  13. }));
*このソースコードは、 ソースコードハイライターで強調表示されました。




Application.Aclクラスは許可システムです。 原則としてZend_Aclに似ています。リソース、ロール、各ロールのアクセス許可を定義して、各リソースにアクセスできます。



一般的に使用される方法:





使用例:





  1. initAcl: function (){
  2. this .constructor.superclass.initAcl.call( this );
  3. //ゲストロールを追加します
  4. this .acl.addRole( new Application.Acl.Role( "guest" ));
  5. //ゲストロールの権限を継承するユーザーロールを追加します
  6. this .acl.addRole( new Application.Acl.Role( "user""guest" ));
  7. //デフォルトでは、すべてへのすべてのアクセスを閉じます
  8. this .acl.deny( null );
  9. this .acl.deny( "guest" );
  10. this .acl.deny( "user" );
  11. //ゲストロールの権限
  12. this .acl.allow( "guest""front / index" );
  13. this .acl.allow( "guest""front / test" );
  14. this .acl.allow( "guest""front / news" );
  15. this .acl.allow( "guest""front / action1" );
  16. this .acl.allow( "guest""front / action2" );
  17. this .acl.allow( "guest""user / login" );
  18. this .acl.allow( "guest""user / noaccess" );
  19. //さらに、ユーザー/ログアウト/制限/インデックスへのアクセスを許可し、ログインを禁止するユーザーロール
  20. this .acl.allow( "user""user / logout" );
  21. this .acl.allow( "user""restricted / index" );
  22. this .acl.deny( "user""user / login" );
  23. this .acl.setErrorRedirect( nullnull 、{controller: 'user' 、action: 'noaccess' });
  24. }
*このソースコードは、 ソースコードハイライターで強調表示されました。




Application.Router-管理されたルーティング。 デフォルトで/ controller / action / paramsの代わりに「美しい」リンクを作成できます。



方法





例:







  1. .................................................. .......................................
  2. this .router.addRoute( new Application.Router.Route( "news""news /:permalink" 、{ "controller"'front'"action"'news'"permalink""[\\ w \\ d \\-] + " }));
  3. .................................................. .......................................
  4. getLink: function (){
  5. return App.route({id: this .get( "Id" )、permalink: this .get( "Permalink" )}、 "news" );
  6. }
  7. .................................................. .......................................
*このソースコードは、 ソースコードハイライターで強調表示されました。




Application.Identity-ユーザーデータ。 このクラスは完全には実装されていません。 デモアプリケーションでは、Ext.state.Managerを使用してセッションデータをCookieに保存します。 ログインすると、認証自体は行われず、オブジェクトはisLoggedプロパティをtrueに設定し、ユーザー名とユーザーロールを保存します。 将来、認証検証用のさまざまなアダプタを使用してZend_Authの完全な類似物を作成する予定です。



このリンクから 、デモアプリケーションを見ることができます。 ブログフィードの表示、システムへのログイン、および「クローズ」セクションへのアクセスを実装します。 ソースコードはここからダウンロードできます代替リンク 、ExtJS配布キットなし)。 ExtJS 3.1で動作し、すべての最新ブラウザーがサポートされています(IE8、Opera10、FF3 +、Safari 4、Chrome)。



提案/希望/アイデア/コメント/修正は受け入れられます。 一般に、私はRIAアプリケーション用の本格的なオープンソースフレームワークをフレームワークから作りたいと思っています。 あなたの中に、Habrの親愛なる読者の中に、興味を持っている人がいるなら、そして欲望と自由な時間があるなら、私たちはプロジェクトチームに歓迎されます。

UPD。 ExtJSライブラリに移動しました



All Articles