【问题标题】:Best practice for 'like' functionality'like' 功能的最佳实践
【发布时间】:2012-09-10 09:51:20
【问题描述】:

我正在开发一个 Flash 游戏网站。我有两个模型:GameUser 以及一个中间表,我在其中保存用户的操作,例如:“用户 1 喜欢游戏 3”。

  1. 我喜欢的功能在哪里最好?
  2. Game 模型中获取当前用户 ID 是一种好习惯吗?还是应该将其作为参数传递?

出于性能原因,我也在游戏表中增加了喜欢的字段。 为了简单起见,我省略了检查用户是否已经喜欢该游戏。
以下是我的选择:

第一版:

$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();    
  }    
}    

【问题讨论】:

  • Is it a good practice to grab current user id in Game model? 没有。or should I pass it as parameter? 是。想一想,现在您将活动用户的 id 存储在会话中,如果稍后将其存储在其他地方会发生什么?更重要的是,您的功能仅对当前活跃用户可用,您不能 like() 对任何其他用户使用。用户 id 是一个外部依赖项,绝对没有理由将您的游戏模型绑定到它,请阅读 dependency injection

标签: php oop model social-media-like


【解决方案1】:

老实说,我不确定这是否是解决此类问题的最佳地点。也许 codereview 更合适。除了所有的事情,IMO,你建议的两种方法都不是“最好的方法”。但与往常一样,这可能是个人的事情。
在我看来,实现 OOP 的最佳方式是尽快将所有数据推送到对象中,并实现一个服务层来处理需要多个查询或多个对象的操作。

如果我假设您使用的是 MVC 模式,那么您的控制器会接收数据。在那里,您实例化一个Game 对象,并将id 设置为123456。您可以将该实例传递给名为fillGameModel(Game $gameInstance) 的服务方法。此方法连接到 DB,并设置 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');
}

同样,通过结果集的循环可以替换为抽象模型类中的方法,该方法将数组作为参数,并将字段名转换为相应的设置器。有足够的抽象空间,我想说;-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-01
    • 2011-08-23
    • 1970-01-01
    • 2010-10-07
    • 2011-04-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多