模型对象的连接共享和结构

时间:2013-12-09 16:24:12

标签: php mongodb oop

我正在编写自己的OOP框架,部分是作为一种学习练习,但知道这个代码库不会消失 - 只会随着我的学习而发展。下面是我的设置看起来像的一些伪代码。在此设置中,我将如何共享数据库连接?用ctrl + f进行“连接”以找到代码中的位置我特别不确定如何构造。

路由文件如下所示:     

switch($urlParameters['action']){
    case 'lading': 
        //etc etc
        break;

    case 'userCP':
        //etc etc
        break;

    case 'dashboard':
    default:
        $page = new dashboard();
        $page->route($urlParameters);
        break;
}

页面看起来像

<?php
abstract class page{ // Page is a mixture of controller and view. Most view logic is frontend, so I do all my controller-view logic here

    public var $models;

    public var $session;
    public var $user;

    function __construct(){
        $this->models = new models();

        $this->session = $this->models->session(new MongoID($_COOKIE['session'])); // Plus some code to prevent session hijacking

        $this->user = $this->models->users($this->session->userID);
    }

    function outputMongoData(){} // Wrapper function used by pages to output Mongo datatypes as regular json (Dates to RFC, IDs to string, rounding floats, etc)

    function template($file, $data){} // This uses output buffering and extract() to use php its self as the templating language. 
}


class dashboard extends page{
    public var $dashboardView;

    function __construct(){
        parent::__construct();

        $this->dashboardView = $this->models->dashboardView($this->user->dashboardViewID);
    }

    function route($urlParams){
        $this->session->updatePageViewCountOrSomething();

        echo $this->template('dashboard.php', [
            'importantData' => $this->dashboardView->someTypeOfDataFromDashboardView,
            'viewCount'     => $this->session->pageViewCount
        ]);
    }
}

模型看起来像

<?php
class models{
    private var $cache = [
        'users' => [],
        'dashboardViews' => [],
        'sessions' => [],
    ];
    // Cache to prevent collisions since we're doing save() vs individual updates, plus saves overhead of querying multiple times (potentially hundreds of times for certain models)

    function __construct(){
        // Potential connection sharing stuff here
    }

    private function modelFactory($collection, $modelName, $identifier){
        $stringID = (string) $identifier;
        if(!isset($this->cache[$collection][$stringID])){
            $this->cache[$collection][$stringID] = new $modelName($identifier);
        }

        return $this->cache[$collection][$stringID];
    }


    public function session(MongoID $sessionID){
        return $this->modelFactory('sessions', 'session', $sessionID);
    }

    public function user(MongoID $userID){
        return $this->modelFactory('users', 'user', $userID);
    }

    public function dashboardView(MongoID $dashboardViewID){
        return $this->modelFactory('dashboardViews', 'dashboardView', $dashboardViewID);
    }
}

abstract class model{
    public var $db;
    public var $collection;

    private var $data = [];

    function __construct($collectionName){
        $this->db = // ??? Not sure how to connect so that I don't have a new connection for every single model..

        $this->collection = $this->db->{$collectionName};
    }

    function __destruct(){
        $this->collection->save($this->data);
    }

    function __get($fieldName){
        return $this->data[$fieldName]; // if isset, etc etc
    }

}

class session extends model{
    // Explanation of schema here
    function __construct(MongoID $sessionID){
        parent::__construct('sessions');

        $this->data = $this->collection->findOne(['_id' => $sessionID]); // or if not found, create..
    }

    function updatePageViewCountOrSomething(){
        $this->data['pageViewCount'] += 1;
        $this->data['orSomething'] = ['something' => 'or another'];
    }
}

class dashboardView extends model{
    // Explanation of schema here

    function __construct(MongoID $dashboardViewID){
        parent::__construct('dashboardViews');

        $this->data = $this->collection->findOne(['_id' => $sessionID]); // or if not found, create..
    }

    function addColumns(){}

    function reorderColumns($newOrder){}
}

1 个答案:

答案 0 :(得分:1)

从您的示例中,models类看起来像是模型实例的工厂。在这种情况下,您可以将它用作连接容器,然后将相应的MongoCollection实例传递给每个模型类而不是集合名称。

我还要注意,在PHP驱动程序中,构建多个MongoClient对象并不存在问题。驱动程序在内部使用持久连接,因此构建具有相同主机/端口/用户/密码组合的五个MongoClient实例仍将仅在后台创建单个网络套接字。您可以使用this slide中的示例和后面的示例自行测试。

model实施的一些常见问题:

  • $data是基础model类的私有,但您可以在子类中访问它。它应该受到保护。
  • 等待__destruct()将对象保存回数据库似乎是一个坏主意,因为它可能发生在脚本的末尾,或者如果对象被垃圾收集,则会在某个时间发生。在应用程序中有一个可预测的点来写入数据似乎更合适。
  • 您可以阅读PHP 5.4+中的SessionHandlerInterface,而不是使用此模型来保存会话数据。这允许您实现标准PHP会话API(例如$SESSION)使用的自定义存储后端(在本例中为MongoDB)。

创建框架(即使是思考练习)之前的一个很好的起点是阅读设计模式。 Anthony Ferrara的blog是一个很好的资源和主题的起点。我还建议学习依赖注入和服务容器,因为这与您关于共享公共资源(例如数据库连接)的原始问题非常相关。 Fabien Potencier在这个问题上表现出色blog series。这篇文章已有几年历史,并且引用了Symfony 1.x实现(Symfony2是他使用的当前模型),但早期的帖子很可能是一个有用的介绍。