PHP MVC Best Practice - перечислить переменную Session для моделирования класса с контроллера или напрямую получить доступ к модели

Наша команда разработчиков обсуждает общую передовую практику: Лучше ли получить доступ к переменной сеанса непосредственно из функции класса модели или передать переменную сеанса из контроллера в качестве аргумента функции в классе модели. Посмотрите на два примера ниже:

Доступ к переменной сеанса непосредственно из класса модели для использования в запросе:

class MyModel {
    public function getUserPrefs($userID) {
        $this->query("SELECT * FROM my_table WHERE id=$_SESSION['userID']");
    }
}

Или передать переменную сеанса из контроллера в функцию класса модели в качестве аргумента функции:

class MyController {
    public function displayUsers() {
        $this->model->getUserPrefs($_SESSION['userID']);
    }
}

class MyModel {
    public function getUserPrefs($userID) {
        $this->query("SELECT * FROM my_table WHERE id=$userID");
    }
}

Проводя его с моделью с контроллера, так что все данные, на которые делается ссылка, поступают из одной точки входа, которая является контроллером.

Что считается лучшей практикой?

Ответ 1

Вторая версия (передача $_SESSION ['userId'] в качестве аргумента метода) приводит к более развязанному классу и, следовательно, более гибкой. Пойдите с ним.

Ответ 2

Вы НИКОГДА не хотите иметь переменные сеанса в своей модели. Вы всегда должны передавать эти переменные в качестве параметров функции в модели. Это также делает ваш код более расширяемым и гибким. Рассмотрим модель, которая получает пользователя по их идентификатору. Вы можете написать такую ​​функцию, как:

function find_by_id() {
  // SELECT * FROM Users WHERE user_id = $_SESSION['user_id'];
}

Однако, что, если вы сейчас хотите создать функциональность администратора с функцией поиска пользователей? Ваша модель жестко запрограммирована для использования сеанса user_id, но вы хотите иметь возможность передавать свой собственный идентификатор. Вам будет лучше:

function find_by_id($id) {
  // SELECT * FROM Users WHERE user_id = $_SESSION['user_id']
}

и в вашем контроллере

$user = Model::find_by_id(1);
//or
$user = Model::find_by_id($_SESSION['user_id']);
//etc

В этом случае, однако, я действительно хотел бы сделать ваш код еще более гибким:

function find($ids) {
  // this is sudo code, but you get the idea
  if(is_array($ids))
    $ids = implode(',', $ids); // if an array of ids was passed, implode them with commas
  SELECT * FROM Users WHERE user_id IN ($ids);
}

Это позволяет вам получить несколько пользователей в ОДНОМ запросе! Это намного эффективнее. Затем, на ваш взгляд:

foreach($users as $user){
  // iterate over each user and do stuff
}

Вы также должны рассмотреть возможность использования класса singelton для пользователя для ограничения загрузки базы данных. Создайте не изменяющийся экземпляр класса под названием CurrentUser (например), например:

class CurrentUser {

  private static $user;

  // we never instantiate it -its singleton
  private function __construct() {}

  public function user() {
    return self::$user;
  }

}

Это действительно базовый пример одноэлементного класса и отсутствует много материала. Если вы хотите узнать больше об одноэлементных классах, отправьте еще один вопрос.

Ответ 3

Имейте в виду, что "сеанс" - это еще одна модель. Однако первый подход неприемлем - что, если вы хотите получить другие предпочтения пользователей, просто чтобы сравнить их с чем-то? Используйте второй подход.

Ответ 4

Я согласен с Seth re. "Вы также должны рассмотреть возможность использования класса singelton для пользователя для ограничения загрузки базы данных. Создайте не меняющийся класс экземпляра под названием CurrentUser".

В моем приложении pseudo-MVC у меня есть класс User (что означает текущий пользователь) с методами для сеанса, получения информации о пользователе, ролях и т.д. и члена класса (что означает любого данного пользователя) с методами регистрации новых пользователей, получения/обновления их свойства и т.д., но не имеет ничего общего с сеансами. Кроме того, это одноэлементный сценарий, поэтому текущий пользователь статичен и не требует большого взаимодействия с БД.

Итак, в моем случае мой контроллер и представления совершают вызовы методам пользователя, например.

User::getId() или User::getGroups().