web-dev-qa-db-ja.com

ユーザークラス:さまざまなユーザーの「サブジェクト」をどのように処理し、それでも単一責任の原則を維持するのですか?

私はユーザークラスを持っています、このクラスは次のようなことを扱います:

  • ログイン(UserAuthenticateModel)
  • ユーザーセッションを処理する:ユーザーログイントークン、セッションで設定されている場合はセッションからユーザーを取得、その他 '(UserSessionsModel)
  • $ thisユーザーオブジェクトに入力するユーザーデータを取得して設定します。 (UserFetchModel)
  • ユーザーデータを(このユーザーオブジェクトに-データベースで)更新および変更します(UserUpdateModel)

私は大声で尋ねています。私が間違っている場合は修正してください。

  1. 「ユーザー」クラス内のある種の「1つだけを処理するもの」の責任はすべてのポイントであり、別のクラスが必要ですか?
  2. 「何か」のオブジェクトにすぎないので、ユーザークラスは「クラス」フォルダーの下にある必要がありますか。また、「ユーザーセッション」や「ユーザー認証」などの他のクラスはモデルと見なす必要がありますか?

いくつかのコードで2つの例を説明します。

  1. セッションを設定する:「セッションで何かを実行する」構成要素にコード全体を貼り付けるだけでなく、UserSessionsModelを、必要なことをすべて実行するメソッドで具体的に使用します。セッションからデータを取得します(存在する場合)。単一の責任-ユーザーセッションの設定/変更、およびユーザーオブジェクトの設定。また、このセッション処理メソッドのいくつかは、他の場所で使用される場合があります(例2)。

コード例:

User class 
{

    public function __construct()
    {
        # look for a user in the session if set
        $this->getFromSession();
    }

    public function getFromSession() 
    {
        # Create UserSession obj
        if ( !$this->UserSessions instanceof UserSessions )
            $this->UserSessions = new \myapp\Models\User\UserSessionsModel();

        $this->UserSessions->getUserFromSession($this);
    }

}

class UserSessionsModel {

    public function getUserFromSession(User $User)
    {
        if (Session::exists(Config::$user)) {

            $session = unserialize(Session::get(Config::$user));

            $User->id             = $session->id; 
            $User->firstName      = $session->firstName; 
            $User->lastName       = $session->lastName; 
            $User->userName       = $session->userName; 
            $User->email          = $session->email; 
            $User->lastLogin      = $session->lastLogin; 
            $User->password       = $session->password; 
            $User->ip             = $session->ip; 
            $User->loginTimestamp = $session->loginTimestamp; 
            $User->isLoggedIn     = $session->isLoggedIn; 

            return $User;
        }
    }



 public function setUserToSession(User $User)
    {
        Session::set(Config::$user, serialize($User));
    }

}
  1. ログイン:これは2つの部分に分かれています:
    • 最初にユーザー資格情報を認証する
    • セキュリティセッションを設定します(トークン、ログインフラグなど)。例1のUserSessionModelを使用します-同じ「サブジェクト」を処理するためです。したがって、どちらもログインメソッドの下にあり(一方はもう一方または別々に-この例では最初に処理します)、どちらも2つの異なる責任があります-1つはユーザー認証をチェックすること、2つ目はセッション/トークンを処理することです。

コード例:

User class {

    // after setting $this->username & $this->password to this object
    public function login()
    {
        if ( !$this->UserAuthenticator instanceof \myapp\Models\User\UserAuthenticatorModel )
            $this->UserAuthenticatorModel = new \myapp\Models\User\UserAuthenticatorModel();

        return $this->UserAuthenticatorModel->login($this);
    }
}


class UserAuthenticatorModel extends Model
{

    public function login(User $User)
    {
        try {

            # Connect to new database with $User->username & $User->password
            ... 

            # If status is connected 
            if ($newConnection) {

                # Check for user credentials data 
                $userData = $this->UserLoginValidation($User->userName, $User->password); 

                # If the result isn't a valid array - EXEPTION  
                if ( (!is_array($userData)) || (empty($userData)) )
                    throw new LoginException("Invalid username ({$User->userName}) or password ({$User->password})");

                if ($userData["require_password_change"] === 1) {
                    $this->set($User, $userData);
                    return true;
                }

                $this->set($User, $userData);
                # Set logged-in security sessions
                $User->UserSessions = new UserSessionsModel();
                $User->UserSessions->setSecuritySession($User);
                # Set User obj to session
                $User->UserSessions->UserToSession($User);

                # Update last_login for this user
                $this->updateLastLogin($User->id, $User->loginTimestamp);

                return true;

            } else {
                throw new LoginException('User does not exist');
                return false;
            }

        } catch (LoginException $e) {
            $e->log($e);
            return false;
        }
    }

PHPここで使用します。

2
Kar19

これを別の方法で分割します。注:以下の特定の言語は使用していません。構文は、組織のアイデアを強調するために使用されています。

認証は独自のものでなければなりません。通常、認証には認証データが返され、その認証データを使用して現在のユーザーを取得します。認証トークンは、さまざまな方法で将来のリクエストにバインドできますが、この例では、認証データを渡します。

class AuthenticationRequest {
    async AuthData login(credentials: Credentials) {
    }

    logout(authData: AuthData) {
    }
}

これで認証が完了したので、ユーザーの取得と設定に別のリクエストクラスを使用します。

class UserRequest {
    async User fetchCurrentUser(authData: AuthData) {
    }

    async User updateUser(user: User, authData: AuthData) {
    }
}

これにより、CredentialsAuthData、およびUserがプレーンな古いデータオブジェクトに変わります。

class Credentials {
    userName: String
    password: String
}

class AuthData {
    token: Data
    loginTimestamp: Date
    userId: String // Maybe not needed.
    ip: IPAddress
}

class User {
    id: String
    userName: String
    firstName: String
    lastName: String
    email: String
    lastLogin: Date
}

基本的な流れは

credentials = Credentials()
credentials->userName = "Foo"
credentials->password = "Bar"

authenticationRequest = AuthenticationRequest()
authData = await authenticationRequest->login(credentials)
credentials = NULL // Release the credentials as soon a possible

userRequest = UserRequest()
user = await userRequest->fetchCurrentUser(authData)

user->firstName = "Bob"
user->lastName = "Roberts"

// NOTE: Assigning user to the result of updateUser() allows the
//       server to control the properties of the updated user.
user = await userRequest->updateUser(user, authData)

authenticationRequest->logout(authData)
authData = NULL
2
Jeffery Thomas