Лучшая практика для "как" функциональности
Я работаю над сайтом флеш игр. У меня есть две модели: Игра и Пользователь и промежуточная таблица, в которой я сохраняю действия пользователя, например: "Пользователю 1 нравится Игра 3".
- Где лучшее место для моей любимой функции?
- Это хорошая практика, чтобы получить текущий идентификатор пользователя в модели игры? или я должен передать его в качестве параметра?
Из соображений производительности я тоже увеличиваю поле лайков в игровом столе. Я не стал проверять, нравится ли пользователю игра, просто для простоты.
Вот мои варианты:
Первая версия:
$user->like(12345);
class User
{
public function like($game_id)
{
$like = new User_Game();
$like->user_id = $this->id;
$like->game_id = $game_id;
$like->save();
$obj = new Game($game_id);
$obj->likes++;
$obj->save();
}
}
Вторая версия:
$game->like(); // by current user
class Game
{
public function like()
{
$like = new User_Game();
$like->user_id = $_SESSION[‘user_id’];
$like->game_id = $this->id;
$like->save();
$this->likes++;
$this->save();
}
}
1 ответ
Честно говоря, я не уверен, что это лучшее место для такого вопроса, как этот. Возможно, codereview лучше подходит. Все вещи в стороне, IMO, ни один из двух вариантов, которые вы предлагаете, не является "лучшим подходом". Но, как всегда, это может быть личным делом.
На мой взгляд, лучший способ использовать ООП - это поместить все ваши данные в объекты как можно скорее и реализовать уровень обслуживания, который выполняет операции, требующие нескольких запросов или нескольких объектов.
Если я могу предположить, что вы используете шаблон MVC, ваш контроллер получает данные. Там вы создаете Game
объект и установите идентификатор в 123456
, Вы можете передать этот экземпляр методу службы с именем fillGameModel(Game $gameInstance)
, Этот метод подключается к БД и устанавливает все остальные свойства Game
объект и возвращает его. То же самое касается User
объект. Оба этих объекта затем могут быть переданы другому методу службы: likeGame(Game $game, User $user)
, Этот метод может позаботиться об остальном.
Лично я бы пошел еще дальше и использовал мапперы для доступа к БД, но сейчас я не буду вдаваться в подробности. Вот пример использования сервиса и более подходящего ОО:
//controller:
$user = new User();
$user->setId($_SESSION['user_id']);
$game = new Game();
$game->setId(123456);//wherever you get this from
$service = new MainService();
$service->userLikes($game,$user);
//service:
public function userLikes(Game $game, User $user)
{
$user = $this->_completeUser($user);
$game = $this->_completeGame($game);
//insert or update whatever data you need...
}
protected function _completeUser(User $user)
{
$db = $this->_getConnection();//asuming PDO, to keep things simple
$query = 'SELECT * FROM my_db.users WHERE id = ?';
$stmt = $db->prepare($query);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
foreach ($row as $field => $value)
{//this implies getters and setters in your model
$user->{'set'.ucfirst(strtolower($field))}($value);
}
return $user;
}
protected function _completeGame(Game $game)
{
$db = $this->_getConnection();
$query = 'SELECT * FROM my_db.games WHERE id = ?';
$stmt = $db->prepare($query);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
foreach ($row as $field => $value)
{//field id becomes "setId" method, field name "setName" etc...
$game->{'set'.ucfirst(strtolower($field))}($value);
}
return $game;
}
//just for show: a pseudo-overloader method, if your models all share the same
//abstract class.
protected function _completeAny(Model_Abstract $model)
{
$modelName = get_class($model);
if (method_exists($this,'_complete'.$modelName))
{
return $this->{'_complete'.$modelName}($model);
}
throw new Exception('No completion method for '.$modelName.' found');
}
Опять же, циклы в наборе результатов могут быть заменены методом в классе абстрактной модели, который принимает массив в качестве аргумента и преобразует имена полей в соответствующие им установщики. Много места для абстракции, я бы сказал;-)