PHP面向對象之領域模型+數據映射器

来源:http://www.cnblogs.com/kerryw/archive/2017/06/16/7021432.html
-Advertisement-
Play Games

/* 這裡要說明一下 因為本人比較懶 博客中相關文章的內容更多的是對一書中代碼的整理和簡單註解方便自己日後複習和參考, 對相關內容感興趣的初學的朋友建議請先閱讀原文。此處的內容只能當成一種學習的補充和參考。謝謝! 因原書中領域模型+數據映射器的示例代碼是連貫在一起的 所以這裡就整理在一起了。 簡單介... ...


/*
這裡要說明一下 因為本人比較懶 博客中相關文章的內容更多的是對<深入PHP面向對象、模式與實踐>一書中代碼的整理和簡單註解方便自己日後複習和參考,
對相關內容感興趣的初學的朋友建議請先閱讀原文。此處的內容只能當成一種學習的補充和參考。謝謝!
因原書中領域模型+數據映射器的示例代碼是連貫在一起的 所以這裡就整理在一起了。
簡單介紹一下我的看法,從資料庫操作的角度看領域模型主要是操作數據表中的單條記錄的而數據映射器是操作整個數據表的數據的。
按原文的解釋數據映射器是一個負責將資料庫數據映射到對象的類,而領域模型象徵著真實世界里項目中的各個參與者,它在數據中通常表現為一條記錄。
廢話不多說,代碼和註解如下:

與領域模型相關的三個數據表結構分別為venue(場所)、space(空間)、event(事件)。
create table  'venue' (
     'id' int(11) not null auto_increment,
     'name' text,
     primary key ('id')
)
create table  'space' (
     'id' int(11) not null auto_increment,
     'venue' int(11) default null,
     'name' text,
     primary key ('id')
)
create table  'event' (
     'id' int(11) not null auto_increment,
     'space' int(11) default null,
     'start' mediumtext,
     'duration' int(11) default null,
     'name' text,
     primary key ('id')
)


*/

//領域模型(這裡只建了一個Venue類用於理解)
namespace woo\domain;

abstract class DomainObject{            //抽象基類
    
    private $id;
    
    function __construct ($id=null){
        $this->id = $id;
    }
    
    function getId(){
        return $this->id;
    }
    
    //原書沒有具體實現,應該是用於獲取對象的從屬對象的,比如venue(場所)相關的space(空間)對象
    //具體的代碼實現中應該從資料庫中查詢了相關數據並調用了Collection類,下麵看到這個類的時候會有一個瞭解
    //而且這個方法的實現應該放在子類中才對
    static function getCollection($type){      
        return array();
    }
    
    function collection(){
        return self::getCollection(get_class($this));
    }
    
}

class Venue extends DomainObject {
    private $name;
    private $spaces;
    
    function __construct ($id = null,$name=null){
        $this->name= $name;
        $this->spaces = self::getCollection('\\woo\\domain\\space'); //這裡應該證明瞭我上述的猜測
        parent::__construct($id);
    }
    
    function setSpaces(SpaceCollection $spaces){
        $this->spaces = $spaces;
    }
    
    function addSpace(Space $space){
        $this->spaces->add($space);
        $space->setVenue($this);
    }
    
    function setName($name_s){
        $this->name = $name_s;
        $this->markDirty();
    }
    
    function getName(){
        return $this->name;
    }
}


//數據映射器(正如原文的解釋數據映射器是一個負責將資料庫數據映射到對象的類)
namespace  woo\mapper;

abstract class Mapper{            //抽象基類
    abstract static $PDO;        //操作資料庫的pdo對象
    function __construct (){
        if(!isset(self::$PDO){
            $dsn = \woo\base\ApplicationRegistry::getDSN();
            if(is_null($dsn)){
                throw new \woo\base\AppException("no dns");
            }
            self::$PDO = new \PDO($dsn);
            self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);
        }
    }
    
    function createObject($array){                    //將數組創建為上述領域模型中的對象
        $obj = $this->doCreateObject($array);        //在子類中實現
        return $obj;
    }
    
    function find($id){                                //通過ID從資料庫中獲取一條數據並創建為對象
        $this->selectStmt()->execute(array($id));
        $array= $this->selectStmt()->fetch();
        $this->selectStmt()->closeCursor();
        if(!is_array($array)){
            return null;
        }
        if(!isset($array['id'])){
            return null;
        }
        $object = $this->createObject($array);
        return $object;    
    }
    
    function insert(\woo\domain\DomainObject $obj){            //將對象數據插入資料庫
        $this->doInsert($obj);
    }
    
    //需要在子類中實現的各抽象方法
    abstract function update(\woo\domain\DomainObject $objet);
    protected abstract function doCreateObject(array $array);
    protected abstract function selectStmt();
    protected abstract function doInsert(\woo\domain\DomainObject $object);
}

//這裡只建立一個VenueMapper類用於理解
class VenueMapper extends Mapper {
    function __construct (){        
        parent::__construct();    //各種sql語句對象    
        $this->selectStmt = self::$PDO->prepare("select * from venue where id=?");
        $this->updateStmt = self::$PDO->prepare("update venue set name=?,id=? where id=?");
        $this->insertStmt = self::$PDO->prepare("insert into venue (name) values(?)");
    }
    
    protected function getCollection(array $raw){        //將Space數組轉換成對象
        return new SpaceCollection($raw,$this);            //這個類的基類在下麵        
    }
    
    protected function doCreateObject (array $array){    //創建對象
        $obj = new \woo\domain\Venue($array['id']);
        $obj->setname($array['name']);
        return $obj;
    }
    
    protected function doInsert(\woo\domain\DomainObject $object){  //將對象插入資料庫
        print 'inserting';
        debug_print_backtrace();
        $values = array($object->getName());
        $this->insertStmt->execute($values);
        $id = self::$PDO->lastInsertId();
        $object->setId($id);
    }
    
    function update(\woo\domain\DomainObject $object){        //修改資料庫數據
        print "updation\n";
        $values = array($object->getName(),$object->getId(),$object->getId());
        $this->updateStmt->execute($values);
    }
    
    function selectStmt(){                    //返回一個sql語句對象
        return $this->selectStmt;
    }
    
}




/*
Iterator介面定義的方法:
rewind()            指向列表開頭    
current()            返回當前指針處的元素
key()                返回當前的鍵(比如,指針的指)
next()                
valid()

下麵這個類是處理多行記錄的,傳遞資料庫中取出的原始數據和映射器進去,然後通過數據映射器在獲取數據時將其創建成對象

*/
abstract class Collection implements \Iterator{
    protected $mapper;            //數據映射器
    protected $total = 0;        //集合元素總數量
    protected $raw = array();    //原始數據
    
    private $result;
    private $pointer = 0;        //指針
    private $objects = array();    //對象集合
    
    function __construct (array $raw = null,Mapper $mapper= null){
        if(!is_null($raw)&& !is_null($mapper)){
            $this->raw = $raw;
            $this->total = count($raw);
        }
        $this->mapper = $mapper;
    }
    
    function add(\woo\domain\DmainObject $object){    //這裡是直接添加對象
        $class = $this->targetClass();
        if(!($object instanceof $class)){
            throw new Exception("This is a {$class} collection");
        }
        $this->notifyAccess();
        $this->objects[$this->total] = $object;
        $this->total ++;
    }
    
    abstract function targetClass();    //子類中實現用來在插入對象時檢查類型的
    
    protected function notifyAccess(){    //不知道幹嘛的
        
    }
    
    private function getRow($num){        //獲取集合中的單條數據,就是這裡通過數據映射器將數據創建成對象
        $this->notifyAccess();
        if($num >= $this->total || $num < 0){
            return null;
        }
        if(isset($this->objects[$num]){
            return $this->objects[$num];
        }
        if(isset($this->raw[$num]){
            $this->objects[$num] = $this->mapper->createObject($this->raw[$num]);
            return $this->objects[$num];
        }
    }
    
    public function rewind(){            //重置指針
        $this->pointer = 0;
    }
    
    public function current(){            //獲取當前指針對象
        return $this->getRow($this->pointer);
    }
    
    public function key(){                //獲取當前指針
        return $this->pointer;
    }
    
    public function next(){            //獲取當前指針對象,並將指針下移    
        $row = $this->getRow($this->pointer);
        if($row){$this->pointer ++}
        return $row;
    }
    
    public function valid(){        //驗證
        return (!is_null($this->current()));
    }
    
}

//子類
class VenueColletion extends Collection implements \woo\domain\VenueCollection{
    function targetClass(){
        return "\woo\domain\Venue";
    }
}


//客戶端
$mapper = new \woo\mapper\VenueMapper();
$venue = $mapper->find(12);
print_r($venue);

$venue = new \woo\domain\Venue();
$venue->setName("the likey lounge-yy");
//插入對象到資料庫
$mapper->insert($venue);
//從資料庫中讀出剛纔插入的對象
$venue = $mapper->find($venue->getId());
print_r($venue);

//修改對象
$venue->setName("the bibble beer likey lounge-yy");
//調用update來更新記錄
$mapper->update($venue);
//再次讀出對象數據
$venue = $mapper->find($venue->getId());
print_r($venue);


//結束

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近開發一個項目,需要調用第三方的介面,第三方提供的數據是xml,我直接使用Array2XML把php數組轉成XML格式。 XML格式如: 由於php數組無法指定多個重覆下標,後面的會覆蓋前面的值,最終只會展示一個值 上面php數組用Array2XML轉成XML,body裡面只會有一個item節點。 ...
  • 本文為公司製作API介面後臺的小結! 1.命名註意事項: 不要使用易混淆的名字,如index,index01... 我喜歡用拼音... 比如: 2.資料庫文件修改: 去database.php里把數據得首碼去掉; 3.獲取請求的值: 4.操作資料庫: (1)原生操作: (2)name查詢: 5.返回 ...
  • 前言: 這幾天剛剛開始學習python,然後就安裝了pycharm,但是那個中文亂碼的問題真是讓人心煩,在網上找了好久,都寫得好亂,今天終於讓我解決了,在這裡總結一下經驗,希望可以幫到你們 問題:如下圖,我的問題主要是在控制台輸入漢字的時候會出現以下亂碼 一般的解決方法 1. 首先如上圖所示,把fi ...
  • Java 數據類型 基本數據類型 數值:int、short、long 字元:char 布爾:boolean 引用數據類型 class(類) interface(介面) 數組[] 所占位元組數 ( ) int:4位元組 char: 規定2位元組。若使用UTF 8編碼,數字和英文等占1個位元組,中文3個位元組;若 ...
  • 目錄 自定義函數 內置函數 文件的操作 練習題 一. 自定義函數 1. 函數的創建 2. 函數的參數 (1)參數的定義 參數是使用通用變數來建立函數和變數之間關係的一個變數。我們都知道函數是用來被調用的,當我們需要給這個函數傳送值的時候,參數用來接收調用者傳遞過來的數據,並保存下來作為一個變數以便後 ...
  • re模塊 序言: re模塊用於對python的正則表達式的操作 標誌位即模式修正符,不改變正則表達式的情況下,通過模式修正符改變正則表達式的含義,從而實現一些匹配結果的調整等功能: 貪婪模式、懶惰模式: match: 從起始位置開始根據模型去字元串中匹配指定內容: 匹配ip地址: search: 根 ...
  • 1. 為重用以及更好的維護代碼,`Python`使用了模塊與包;一個`Python`文件就是一個模塊,包是組織模塊的特殊目錄(包含`__init__.py`文件)。 2. 模塊搜索路徑,`Python`解釋器在特定的目錄中搜索模塊,運行時`sys.path`即搜索路徑。 3. 使用`import`關... ...
  • 編譯器是怎麼實現引用類型的呢?本篇文章複習了const常量和指針,在此基礎上推測了引用類型的本質。旨在加深對語言的理解,希望對你有所幫助。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...