xFrameの歴史は単一の注文から始まりました。 クライアントは、自分のWebサイトに財務表示システムを実装することを望んでいました。 レポート。 彼はすでにExtJSに精通しており(サイト管理パネルが実装されています)、ライブラリが好きで、ExtJSグリッドの形式でレポートを表示したいと考えていました。 システムの追加要件は、さまざまなユーザーグループのレポートを表示するためのアクセス権の制限でした。 したがって、リソースへのアクセスの認証と配布を行うRIAアプリケーションを実装するタスクに直面しました。
サイトの管理パネルはそのような機能をサポートしていましたが、クライアントに適さないWebDesktopの形式で作成されました。 そのため、システムの開発をゼロから始めました。 当時、私はK. Zervasの本「Web 2.0:PHPでアプリケーションを作成する」を読んでいて、そこに記述されているZend Frameworkの精神に触発されました。 そして、ZFとまったく同じようなものを作成したかったのです。 そして、私はそれをやった。 基本的な機能は2日以内に実装され、デバッグには数日かかりました。 その後、報告システム自体の実装後、自由時間にフレームワークを提示可能な状態にし、一般に提出することにしました。
「コード」名xFrame (eXtjs FRAMEwork)と呼ぶ限り、フレームワークの最終的な名前はまだ思いつきません。 xFrameの実装:
- ZFおよびクラスの命名で受け入れられたファイルシステムの構成(クラス名はFSでそのパスを繰り返します。スラッシュはドットに置き換えられます)
- カスタムシステムコンポーネントの標準名前空間。 コントローラーの場合-Application.controllers、コンポーネントの場合-Application.components、モデルの場合-Application.models。
- ライブラリコードとアプリケーションコードの分離のZFが受け入れた概念。 XFrameコードは1つのフォルダー(js / lib / xframeなど)に配置され、アプリケーションコードは別のフォルダー(js / xframe-appなど)に配置されます
- モデルビューコントローラーパターン
- 標準ZF参照システム(http:// <app_url> /コントローラー/アクション/ param1 / value1 / param2 / value2 / ....)
- URIフラグメントのアドレス指定(http:// <app_url> /#トークン)。これにより、ページをリロードせずに動作するAJAXアプリケーションの利便性を維持しながら、アプリケーションの状態をリンクに保存できます。
- モデルビューコントローラーアーキテクチャ
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 .
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 .
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 .
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 .
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 .
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 .
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 .
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 .
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 .
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オブジェクトへのリンク。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- Application.controllers.FrontController = Ext.extend(Application.controllers.Abstract、{
- .................................................. .................................................. ...................
- newsAction: function ( params 、app、panel){
- panel.add({
- xtype: 'Application.components.NewsViewer' 、
- newsPermalink: params .permalink
- });
- }、
プレゼンテーション機能は完全にExtJSコンポーネントに実装されています。 アプリケーションが初期化されると、ビューポートが作成され、ページ上の指定された場所にレンダリングされます。 コントローラー/アクションを変更すると、出力領域が変わります。 他のすべてのコンテンツは変更されません。 アクションメソッドを呼び出す前に、コンポーネントに関する出力領域がクリアされ、アクション自体がそれに必要なコンポーネントを追加できます。その後、アプリケーションはビューポートを再描画します。
システムの構造レベルでは、次の主要コンポーネントが区別されます。
Applicationクラスは、 アプリケーションの基盤です。 このクラスでは、システムの他のすべてのコンポーネントがカプセル化されます。
- App.acl-Application.Aclへのリンク(許可システム)
- App.router-Application.Routerへのリンク(カスタムルーティング)
- App.auth-Application.Identity(ユーザーデータ)へのリンク
- App.sessionManager-セッションマネージャーへのリンク
- App.viewport-出力エリアへのリンク
一般的に使用される方法:
- request-AJAXリクエストを実行します
- log-変数をコンソールに表示します
- リダイレクト-指定されたトークンへのリダイレクト(URIの変更あり)
- forward-指定されたトークンへのリダイレクト(URIを変更せずに)
アプリケーションを作成するとき、このクラスを継承し、必要な初期化メソッドを事前定義する必要があります。
*このソースコードは、 ソースコードハイライターで強調表示されました。
- var App = new (Ext.extend(Application、{
- renderTo: 'app' 、
- autoRun: true 、
- initAcl: function (){
- this .constructor.superclass.initAcl.call( this );
- this .acl.addRole( new Application.Acl.Role(....................));
- .................................................. ....................
- }、
- initRouter: function (){
- this .constructor.superclass.initRouter.call( this );
- この .router.addRoute( 新しい Application.Router.Route(....................................} ));
- }
- }));
Application.Aclクラスは許可システムです。 原則としてZend_Aclに似ています。リソース、ロール、各ロールのアクセス許可を定義して、各リソースにアクセスできます。
一般的に使用される方法:
- addRole(新しいApplication.Acl.Role(ロール名[、baseRole]))-ロールを追加します。 ロールの作成時に基本ロールが指定されている場合、そのロールはそのすべての権限をオーバーレイします
- addResource(新しいApplication.Acl.Resource(resourcename))-リソースを追加します。 コントローラーとアクションのセットもリソースですが、自動的に追加されます
- allow / deny(ロール、リソース)-リソースリソースへのロールロールのアクセスを許可/拒否します。 この場合、パラメーターのいずれか(または両方が指定されていない場合)、アクセス許可はグローバルに設定されます。 allow()-すべての人にデフォルトのアクセス権を与え、allow(null、リソース)-すべての人にリソースにアクセス権を与え、allow(ロール)-すべてのロールにアクセス権を付与
- setErrorRedirect(role、resource、{controller: 'error_controller'、action: 'error_action'})-ロールroleにリソースresourceへのアクセス許可がない場合に呼び出されるアクションを示します
使用例:
*このソースコードは、 ソースコードハイライターで強調表示されました。
- initAcl: function (){
- this .constructor.superclass.initAcl.call( this );
- //ゲストロールを追加します
- this .acl.addRole( new Application.Acl.Role( "guest" ));
- //ゲストロールの権限を継承するユーザーロールを追加します
- this .acl.addRole( new Application.Acl.Role( "user" 、 "guest" ));
- //デフォルトでは、すべてへのすべてのアクセスを閉じます
- this .acl.deny( null );
- this .acl.deny( "guest" );
- this .acl.deny( "user" );
- //ゲストロールの権限
- this .acl.allow( "guest" 、 "front / index" );
- this .acl.allow( "guest" 、 "front / test" );
- this .acl.allow( "guest" 、 "front / news" );
- this .acl.allow( "guest" 、 "front / action1" );
- this .acl.allow( "guest" 、 "front / action2" );
- this .acl.allow( "guest" 、 "user / login" );
- this .acl.allow( "guest" 、 "user / noaccess" );
- //さらに、ユーザー/ログアウト/制限/インデックスへのアクセスを許可し、ログインを禁止するユーザーロール
- this .acl.allow( "user" 、 "user / logout" );
- this .acl.allow( "user" 、 "restricted / index" );
- this .acl.deny( "user" 、 "user / login" );
- this .acl.setErrorRedirect( null 、 null 、{controller: 'user' 、action: 'noaccess' });
- }
Application.Router-管理されたルーティング。 デフォルトで/ controller / action / paramsの代わりに「美しい」リンクを作成できます。
方法
- addRoute(新しいApplication.Router.Route(名前、パス、パラメーター))-新しいルーティングルールを追加します。 Application.Router.RouteクラスはZend_Controller_Router_Route_Regexに似ています-パラメーターのプレースホルダーはパスに書き込まれ、正規表現と定数パラメーターはパラメーターに指定されます
- route(params、route)-ルートルールとparamsパラメーターを使用してリンクを生成します
例:
*このソースコードは、 ソースコードハイライターで強調表示されました。
- .................................................. .......................................
- this .router.addRoute( new Application.Router.Route( "news" 、 "news /:permalink" 、{ "controller" : 'front' 、 "action" : 'news' 、 "permalink" : "[\\ w \\ d \\-] + " }));
- .................................................. .......................................
- getLink: function (){
- return App.route({id: this .get( "Id" )、permalink: this .get( "Permalink" )}、 "news" );
- }
- .................................................. .......................................
Application.Identity-ユーザーデータ。 このクラスは完全には実装されていません。 デモアプリケーションでは、Ext.state.Managerを使用してセッションデータをCookieに保存します。 ログインすると、認証自体は行われず、オブジェクトはisLoggedプロパティをtrueに設定し、ユーザー名とユーザーロールを保存します。 将来、認証検証用のさまざまなアダプタを使用してZend_Authの完全な類似物を作成する予定です。
このリンクから 、デモアプリケーションを見ることができます。 ブログフィードの表示、システムへのログイン、および「クローズ」セクションへのアクセスを実装します。 ソースコードはここからダウンロードできます ( 代替リンク 、ExtJS配布キットなし)。 ExtJS 3.1で動作し、すべての最新ブラウザーがサポートされています(IE8、Opera10、FF3 +、Safari 4、Chrome)。
提案/希望/アイデア/コメント/修正は受け入れられます。 一般に、私はRIAアプリケーション用の本格的なオープンソースフレームワークをフレームワークから作りたいと思っています。 あなたの中に、Habrの親愛なる読者の中に、興味を持っている人がいるなら、そして欲望と自由な時間があるなら、私たちはプロジェクトチームに歓迎されます。
UPD。 ExtJSライブラリに移動しました