4

CakePHP 2.2を使用して、各クライアントが独自のデータの「レルム」を持ち、他のデータが表示されないアプリケーションを構築しています。たとえば、クライアントには、ユーザー、コース、請負業者、および仕事のセットがあります。グループはクライアント間で共有されますが、グループに対してアクションを実行することはできません。グループでできるすべてのクライアントは、グループをユーザーに割り当てることです。したがって、管理者(ACLを使用)は、同じクライアントIDからのデータのみを管理できます。

私のすべてのオブジェクト(もちろんグループを除く)にはclient_idキーがあります。

今、私はこれを成し遂げて実際にうまく機能させるための1つの方法を知っていますが、それは少し汚いようで、もっと良い方法があるかどうか疑問に思っています。プロジェクトの初期段階でCakePHPを初めて使用するので、私はそれを正しく理解したいと思っています。

これは私が今それをしている方法です:

1-ユーザーがログインします。ユーザーのテーブルのデータに従って、彼のclient_idがセッションに書き込まれます。

$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);

2- AppControllerには、そのセッションIDを特定のパラメーターと比較する保護された関数があります。

protected function clientCheck($client_id) {
    if ($this->Session->read('User.client_id') == $client_id) {
        return true;
    } else {
        $this->Session->setFlash(__('Invalid object or view.'));
        $this->redirect(array('controller' => 'user', 'action' => 'home'));
    }
}

3-さまざまなインデックスアクション(各インデックス、各関連コントローラー)を使用して、paginate条件を使用してclient_idを確認します。

public function index() {
    $this->User->recursive = 0;
    $this->paginate = array(
         'conditions' => array('User.client_id' => $this->Session->read('User.client_id'))
    );
    $this->set('users', $this->paginate());
}

4-他のアクションでは、この方法でHTTPリクエストタイプをチェックする前にclient_idをチェックします。

$user = $this->User->read(null, $id);
$this->clientCheck($user['User']['client_id']);
$this->set('user', $user);
4

3 に答える 3

1

コンセプトは良いです-それは「汚い」ではありません、そしてそれは私がそのような状況を処理した方法とほとんど同じです。

冗長なコードが数行あります。初め:

$this->Auth->user('id')

このメソッドは、実際にログインしているユーザーの任意のフィールドを取得できるため、次のことができます。

$this->Auth->user('client_id')

だからあなたの2行:

$user = $this->User->read(null, $this->Auth->user('id'));
$this->Session->write('User.client_id', $user['User']['client_id']);

必要ありません。ユーザーを再読み込みしたり、セッションに何かを書き込んだりする必要はありません。必要なときにいつでもAuthからclient_idを直接取得するだけです。

実際、http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-userを読むと、コンテキスト外からも取得できるとさえ言われています。次のような静的メソッドを使用したコントローラーの

AuthComponent::user('client_id')

それはあなたがそれを必要としているようには見えませんが。

于 2012-11-06T22:36:28.693 に答える
1

モデルのbeforeFind関数に何かを配置することにより、モデルのすべての検索にclient_id条件を適用することもできます。

たとえば、ユーザーモデルでは、次のように実行できます。

function beforeFind( $queryData ) {

    // Automatically filter all finds by client_id of logged in user
    $queryData['conditions'][$this->alias . '.client_id'] = AuthComponent::user('client_id');

    return $queryData;
}

AuthComponent :: user('client_id')がモデルで機能するかどうかはわかりませんが、理解できます。これにより、モデル内のすべての検索にこの条件が自動的に適用されます。

モデルでbeforeSaveを使用して、新しいレコードでそのclient_idを自動的に設定することもできます。

于 2012-11-07T21:07:58.230 に答える
0

私はPostgreSQLを使用しているので、私の答えはデータベースエンジン固有かもしれません。私のプロジェクトでは、mysql用語でクライアントごとに異なるスキーマを使用しました。これは、クライアントごとに個別のデータベースになります。

パブリックスキーマ(共通データベース)には、すべてのクライアント(この場合はclient_idを持たないオブジェクト)間で共有する必要のあるすべてのデータ(変数定数、プロファイル設定など)を格納します。

会社固有のモデルで私は定義します

public $useDbConfig = 'company_data';

メソッドではController/AppController.php beforeFilter()、ログインしたユーザーに応じてスキーマを設定するためのこのコードがあります。

if ($this->Session->check('User.Company.id')) {
    App::uses('ConnectionManager', 'Model'); 
    $dataSource = ConnectionManager::getDataSource('company_data');
    $dataSource->config['schema'] = 
        'company_'.$this->Session->read('User.Company.id');
}

ご覧のとおり、使用済みの会社に応じて、dataSourceをその場で更新します。これは、会社に関連するデータのみがそのスキーマ(データベース)に格納されるため、クエリへのcompany_idの関与を除外します。また、これにより、プロジェクトをスケーリングする機能が追加されます。

このアプローチの欠点は、構造変更時にすべてのデータベース構造を同期するのが面倒になることですが、データのエクスポート、すべてのデータベースの削除、新しいレイアウトでの再作成、およびデータの再インポートを使用して行うことができます。列名を含む完全な挿入を含むデータをエクスポートする必要があります。

于 2012-11-07T23:01:12.100 に答える