その背景から、ある種のデータ管理システムを開発する必要がありました。 当然、データはDBMSに保存されるため、Webで管理する必要があります。 私はフレームワークに夢中になりたくなかったので、PHPクイックコーディング、またはsmartyなどの既成の開発に基づいたレンダリングを使用したMVCの選択はあまりよくありませんでした。 しかし、ほぼ同時に、extJS(別名Sencha)やqooxdooなどのプロジェクトに注目しました。これらのプロジェクトにより、退屈なHTMLレイアウト、HTML / XML生成、XSLT変換、およびその他多くの「怖い」ことなく本格的なWebアプリケーションを作成できます»MVCおよびPHPのbydcode固有のもの。 したがって、次のアクションプランは成熟しています。
- extJSまたはqooxdooユーザーインターフェイス
- PHPモデル
- 接続はそれらの間のXML \ JSON RPCです
軽量で、独立した、理解しやすい、シンプルで、ハーフキックで動作するものを探していました。 このようなプロジェクトはcode.google.com/p/json-xml-rpcで見つかりました。これは、PHPのサーバーとJavaScriptのクライアントを使用した、かなり柔軟でシンプルなRPCの実装で、XMLとJSONの両方で動作し、同期、非同期呼び出し。これは後で重要ではないことが判明しました。 次のステップは、RPC、およびロールとアクセス権の分配システムを拡張することでした。 これについて詳しく説明したいと思います。 だから。
そもそも、私はOOPスクールの支持者であり、一般に、オリジナルのC ++で記述します。その結果、そのようなPHPやJavaScript自体は、コードで許可または禁止することに関して時々怒り狂います。 それにもかかわらず、OOPで再利用されるコードを書くことは可能であるだけでなく、必要でもあると思います。 そして、何を書いてもかまいません。 そのため、このシステム用に一連のインターフェイスとその実装が開発されました。これは、セッション、承認、ユーザー、ロールなどの作業の側面を反映します。また、PHPクラスをJavaScriptに自動的に転送するだけでなく、メソッド呼び出しまでこれらのクラスにアクセス権を割り当てます。
まず、PHPとJavaScriptでタスクとコードを設定する観点から見た様子を示します。 単純なクラスがあるとしましょう:
クライアント側のJavaScriptでまったく同じ機能を持つまったく同じクラスを作成し、次のように記述します。class Test {
public function mul ($param1, $param2) {
return $param1 * $param2;
}
}
* This source code was highlighted with Source Code Highlighter .
これを行うには、現在のバージョンでは、次の内容のファイルを作成する必要があります(良識のaip / Test.phpで呼び出しましょう):var test = new Test();
var result = test.foo(1,2);
* This source code was highlighted with Source Code Highlighter .
そして、そのような計画の別のファイルにテストJavaScriptを作成してみましょう(これ以上テストを行わずにtest.htmlと呼びます)。include '../base/IRPCProxy.inc' ;
class Test extends IRPCProxy {
public function mul ($param1, $param2) {
return $param1 * $param2;
}
}
IRPCProxy::populate( new Test());
* This source code was highlighted with Source Code Highlighter .
ご覧のとおり、PHPの観点からもJavaScriptaの観点からも大きな変化はありません。 PHPで必要なクラスをIRPCProxyから継承し、「特別な方法」でJavaScriptのテスト変数を初期化するだけです。 当然、JavaScriptコードは完全ではありませんが、最終的に、そのようなリモートオブジェクトの使用は、コードでの使用とまったく同じに見えます。var test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
var result = test.mul (19, 7);
* This source code was highlighted with Source Code Highlighter .
今すぐアクセス権。 RPCシステム自体は、セッションについても、ユーザーについても、当然のことながら、その役割についてもまったく知りません。 これらはすべて、私が開発したクラスとインターフェースによって、いつの間にか簡単に制御されます。 主なエンティティ:
- ユーザー、彼の役割と承認
- セッション、そのデータと承認
- RPCプロキシと派生クラスのメソッドへのアクセス
ユーザーから始めましょう。 怠け者になり、その承認は正しいログインの確認とロールの変更(ファイルimpl / TestUser.inc)のみで構成されます。
次に、セッションが必要です。 データを他のプロジェクトと混同しないように、セッションは特別な接頭辞「test」(ファイルimpl / TestSession.inc)で初期化されます:/**
* RPC user implementation
* @author alexander.voronin@gmail.com
*/
class TestUser extends IRPCUser {
/**
* @see IRPCUser::authorize()
*/
public function authorize ( $login, $password ) {
if ( $login == "test" ) {
$ this ->login = $login;
$ this ->role = "admin" ;
return true ;
} else {
IRPCProxy::logText( "Authorization failed for user '$login' - invalid login" );
return false ;
}
}
};
* This source code was highlighted with Source Code Highlighter .
最後に、プロキシの実装自体は、標準のユーザーとセッションではなく、独自の(impl / RPCTestProxy.incファイル)を使用していることを「認識」する必要があります。require_once '../base/IRPCSession.inc' ;
/**
* RPC session implementation
* @author alexander.voronin@gmail.com
*/
class TestSession extends IRPCSession {
/**
* Reload CTOR and create own session namespace
*/
function __construct () {
parent::__construct( "test" );
}
};
* This source code was highlighted with Source Code Highlighter .
これで、PHPのRPCコードでロールごとに権利を配布する準備が整いました。 現在の実装の観点から見ると、これは要求に応じて1回行われ、受信したコードはセッションデータにキャッシュされます。 キャッシュされたコードのキーは複雑で、セッションプレフィックスとユーザーロールで構成されているため、ユーザーが作業中にロールを変更すると、不足しているコードが自動的に生成されます。 コードが既に存在する場合、セッションを破棄するか、キャッシュされたコードを「直接」実行することによってのみキャッシュをリセットできます。もちろん、コードを明確で読みやすいものにしない方がよいことに注意してください。 そのため、権利(api / Test.phpファイル)を配布します。// base
require_once '../base/IRPCProxy.inc' ;
// implementations
require_once 'TestSession.inc' ;
require_once 'TestUser.inc' ;
/**
* RPC proxy implementation
* @author alexander.voronin@gmail.com
*/
class TestProxy extends IRPCProxy {
/**
* @see IRPCProxy::createSession()
* @return TestSession
*/
public function createSession() {
return new TestSession();
}
/**
* @see IRPCProxy::createUser()
* @return TestUser
*/
public function createUser() {
return new TestUser();
}
}
* This source code was highlighted with Source Code Highlighter .
コードからわかるように、クラスのメソッドへのアクセスは、その名前とユーザーの現在のロールに基づいて判断するだけです。 また、sessionLoginメソッドを追加しました。これにより、パスワードとsessionLogoutなしでログインできるようになり、明らかにセッションが終了します。 内部で何が起こっているか心配する必要はありません。すべてがそこで機能し、承認に成功すると、ユーザーは上記で合意したように役割を変更します。 これが、今後の作業に必要なすべてです。 JavaScriptテストを展開して、すべてがどのように機能するかを示します。<?php
include '../impl/RPCTestProxy.inc' ;
class Test extends RPCTestProxy {
function haveAccess ( $method ) {
switch ( $ this ->getUser()->getRole()) {
case "anonymous" :
switch ( $method ) {
case "mul" :
case "getRole" :
case "sessionLogin" :
return true ;
default :
return false ;
}
case "admin" :
return true ;
default :
return false ;
}
}
public function mul ($param1, $param2) {
return $param1 * $param2;
}
public function getRole () {
return $ this ->getUser()->getRole();
}
public function sessionLogin ($login) {
if ( $ this ->authorize($login, "" )) {
return true ;
} else {
return false ;
}
}
public function sessionLogout () {
$ this ->logout();
}
public function forAdmins () {
return "hello admin" ;
}
}
IRPCProxy::populate( new Test());
?>
* This source code was highlighted with Source Code Highlighter .
コードからわかるように、実行の過程で、ユーザーはロールを2回変更します。 承認後、メソッドのリストを更新するためにRPCオブジェクトを再作成する必要があります。 ログイン後、すべてのデータを含むセッションは破棄され、ユーザーロールは匿名に変更されます。 このようなコードをブラウザで実行した典型的な結果は次のとおりです。// simple log
function log ( msg ) {
document .write( 'LOG: ' + msg + '\n' );
}
var start = new Date();
// RPC init
var test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
log( 'Test calls: ' + test.system.listMethods());
log( 'Role: ' + test.getRole());
var result = test.mul (19, 7);
log ( 'Test result: ' + result );
// try to login with invalid credentials
if ( !test.sessionLogin ( 'vasya' )) {
log ( 'Login failed!' );
} else {
log ( 'Login success!' );
}
// check role after login
log( 'Role: ' + test.getRole());
// now try to login with valid credentials
if ( !test.sessionLogin ( 'test' )) {
log ( 'Login failed!' );
} else {
log ( 'Login success!' );
}
// check role after login
log( 'Role: ' + test.getRole());
// must reinit RPC to get access to new methods
test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
log( 'Test calls: ' + test.system.listMethods());
log( 'Admin test: ' + test.forAdmins());
// logout now
log ( 'Logout now...' );
test.sessionLogout();
// check role after login
log( 'Role: ' + test.getRole());
// check timing
var stop = new Date();
var testTime = stop.getTime() - start.getTime ();
log ( 'Test time: ' + testTime + 'ms' );
* This source code was highlighted with Source Code Highlighter .
LOG: Test calls: mul,getRole,sessionLogin,system.setJSONDateFormat,system.setDBResultIndexType
LOG: Role: anonymous
LOG: Test result: 133
LOG: Login failed!
LOG: Role: anonymous
LOG: Login success!
LOG: Role: admin
LOG: Test calls: mul,getRole,sessionLogin,sessionLogout,forAdmins,system.setJSONDateFormat,system.setDBResultIndexType
LOG: Admin test: hello admin
LOG: Logout now...
LOG: Role: anonymous
LOG: Test time: 212ms
その結果、HTMLレイアウトをまったく使用せずに動作するWebシステムを手に入れました。 データモデルのコードとその処理を純粋な非クラウドPHPで記述し、上記のRPCシステムを介してアクセスできるようにします。クライアントは、ウィンドウ、リベット、フリルを備えた通常のqooxdooアプリケーションです。 そのようなシステムの場合、MVC世紀は終わりを迎え、彼らが言うように神に感謝します!
結論として、パフォーマンスについていくつかお話したいと思います。 確かに-RPCは遅いです。 ただし、非同期RPC要求を使用すると、RPC呼び出し時にブラウザーがフリーズするのをなくすことができます。もちろん、コード自体の記述方法に注意する必要があります。 おそらく、ダースのRPC呼び出しを1つに結合するか、メソッドの結果として返されるものについて考える必要があります。
上記の例全体とRPCラッパーコードは、 depositfiles.com / files / xsnid5wg9からダウンロードできます。どこかで使用することを考えている場合は、作成者に問い合わせてください。 ありがとう
あなたに良い、美しく、安定したコード!