douyan8070 2013-12-09 16:24
浏览 38

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

I'm writing my own OOP framework, partially as a learning exercise, but knowing this codebase isn't going to disappear - only evolve as I learn. Below is some psuedocode of what my setup looks like. In this setup, how would I share DB connections? Do a ctrl+f for "connection" to find the places in the code I'm specifically unsure of how to structure.

A routing file would look like this:

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

    case 'userCP':
        //etc etc
        break;

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

A page would look like

<?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
        ]);
    }
}

And the models look like

<?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条回答 默认 最新

  • dongshuobei1037 2014-01-02 20:16
    关注

    From your example, it looks like the models class is functioning as a factory for your model instances. In that case, you could use it as the connection container and then pass the appropriate MongoCollection instance to each model class instead of the collection name.

    I'll also note that in the PHP driver, there is not really a concern with constructing multiple MongoClient objects. The driver uses persistent connections internally, so constructing five MongoClient instances all with the same host/port/user/password combination will still only create a single network socket behind the scenes. You can test this out for yourself using the example in this slide and the one following.

    Some general concerns with your model implementation:

    • $data is private to the base model class, but you access it in the child classes. It should probably be protected.
    • Waiting until __destruct() to save an object back to the database seems like a bad idea, as it could happen at the end of the script or sometime earlier if the object is garbage-collected. Having a predictable point in the application to write data seems preferable.
    • Instead of using this model for persisting session data, you can read up on the SessionHandlerInterface in PHP 5.4+. That allows you to implement a custom storage backend (MongoDB in this case) to be used by the standard PHP session API (e.g. $SESSION).

    A great starting point before creating a framework (even as a thought exercise), would be to read up on design patterns. Anthony Ferrara's blog is a great resource and starting point for the subject. I would also suggest learning about dependency injection and service containers, as that's very relevant to your original question about sharing a common resource (e.g. database connection). Fabien Potencier did a great blog series on the subject. The article is a few years old and references the Symfony 1.x implementation (Symfony2 is the current model he uses), but the early posts will likely serve as a useful introduction.

    评论

报告相同问题?

悬赏问题

  • ¥15 init i2c:2 freq:100000[MAIXPY]: find ov2640[MAIXPY]: find ov sensor是main文件哪里有问题吗
  • ¥15 运动想象脑电信号数据集.vhdr
  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景