天天看點

ZendFramework2學習筆記 “單表多對象”的CRUD操作、“多表單對象”的CRUD操作一)單表單對象的CRUD操作 二)單表多對象的CRUD操作 三)多表單對象的CRUD操作

    CRUD是指增加(Create)、讀取(Retrieve)、更新(Update)和删除(Delete)幾個單詞的首字母簡寫。

    在ZendFramework2項目中建立一個子產品Test。

    Test子產品的module.config.php的控制器和路由這樣配置:

<span style="font-size:18px;"> 'controllers' => array(
         'invokables' => array(
             'Test\Controller\Test' => 'Test\Controller\TestController',
         ),
     ),
    'router' => array(
         'routes' => array(
             'test' => array(
                 'type'    => 'segment',
                 'options' => array(
                     'route'    => '/test[/][:action][/:id]',
                     'constraints' => array(
                         'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
                         'id'     => '[0-9]+',
                     ),
                     'defaults' => array(
                         'controller' => 'Test\Controller\Test',
                         'action'     => 'tdb',
                     ),
                 ),
             ),
         ),
     ),</span>
           

一)單表單對象的CRUD操作

    在資料庫中建立這樣一個表:

CREATE TABLE `a` (

  `name` varchar(255) NOT NULL,

  `content` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`name`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    單表單對象的CRUD操作實作起來相對簡單,可以參考ZendFramework2的例子程式Album子產品。

    在Modules\Test\src\Model\下建立檔案“A.php”和“ATable.php”

    A.php内容如下:

namespace Test\Model;

class A {
    
    public $name;
    public $content;
    
    
    public $type;
    
    public function __construct() {
    }

    public function exchangeArray($data) {
        $this->name = empty($data['name']) ? null : $data['name'];
        $this->content = empty($data['content']) ? null : $data['content'];

        
        $this->type = empty($data['type']) ? null : $data['type'];
    }
     
    //binding Model to Form needs this method 
    public function getArrayCopy() {
        return get_object_vars($this);
    }
     
}
           

其中exchangeArray函數會被架構調用,其參數$data是一個從表a擷取的以表a的字段名/字段值為key/value的關聯數組,該函數用于填充對象。

其中getArrayCopy函數是将對象按對象屬性/屬性值為key/value轉換為關聯數組。

    ATable.php類容如下:

namespace Test\Model;

use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Where;
use Zend\Db\Sql\Predicate\Operator;

class ATable {
    
    protected $tableGateway;
    
    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }
     
    public function select($where=null) {
        $resultSet = $this->tableGateway->select($where);
        return $resultSet;
    }
        
    public function update($a) {
        if (!($a instanceof A)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $a->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            $data = $a->getArrayCopy();
            unset($data['name']);//移除主鍵
            try {
                $ret = $this->tableGateway->update($data, array('name' => $a->name));
                if ($ret == 1 || $ret == 0) {
                    return true;
                }
            } catch (Exception $ex) {

            }
        }        
        return false;
    }
    
    public function insert($a) {
        if (!($a instanceof A)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $a->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            return false;
        }
        try {
            $data = $a->getArrayCopy();
            $ret = $this->tableGateway->insert($data);
            if ($ret == 1) {
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }     
     
    public function delete($a) {
        if (!($a instanceof A)) {
            return false;
        }
        try {
            $ret = $this->tableGateway->delete(array('name' => $a->name));
            if ($ret == 1) {
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }
}
           

該類是表a的操作類,具體實作select、update、delete、insert操作。

打開Module\Test\Module.php檔案,添加getServiceConfig函數:

public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Test\Model\ATable' =>  function($sm) {
                    $tableGateway = $sm->get('ATableGateway');
                    $table = new ATable($tableGateway);
                    return $table;
                },
                'ATableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new A());
                    return new TableGateway('a', $dbAdapter, null, $resultSetPrototype);
                },
        );
    }
           

    其中,ResultSet->setArrayObjectPrototype就是執行ATable->select函數時,ZendFramework2架構自動将表記錄轉換為的對象原型。

    并添加類引用:

use Test\Model\A;
use Test\Model\ATable;
           

    在Module\Test\src\Test\Controller\TestController.php中添加對象A的CRUD四個控制器:

namespace Test\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Sql\Where;
use Zend\Db\Sql\Predicate\Operator;

use Test\Model\A;

class TestController extends AbstractActionController {
    
    protected $aTable;
    
    public function getATable() {
        if (!$this->aTable) {
            $sm = $this->getServiceLocator();
            $this->aTable = $sm->get('Test\Model\ATable');
        }
        return $this->aTable;
    }
    
    public function selectAction() {      
        $name = $this->params()->fromQuery('name');
        if (!empty($name)) {
            $where = new Where();
            $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $name));
        }
        
        return new ViewModel(array(
            'as' => $this->getATable()->select((isset($where)?$where:null)),
        ));
    }
     
    public function insertAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        $a = new A;
        $a->name = $name;
        $a->content = "content";
        $ret = $this->getATable()->insert($a);
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    
    public function updateAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        $content = $this->params()->fromQuery('content');
        if (empty($content)) {
            $content = 'content';
        }
        $a = new A;
        $a->name = $name;
        $a->content = $content;
        $ret = $this->getATable()->update($a);
         
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    
    public function deleteAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        
        $a = new A;
        $a->name = $name;
        $ret = $this->getATable()->delete($a);
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    
}
           

最後在Module\Test\view\test\test\目錄下建立select.phtml、insert.phtml、update.phtml和delete.phtml:

//select.phtml

 $title = 'select';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
    foreach ($this->as as $a) {
        echo $this->escapeHtml($a->name);
        echo "------";
        echo $this->escapeHtml($a->content);
        echo "<br/>";
    }


 //insert.phtml

  $title = 'insert';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


 //update.phtml
 $title = 'update';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


 //delete.phtml
 $title = 'delete';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";
           

讀取(Retrieve)使用http://xxxx/test/select或者http://xxx/test/select?name=y。

增加(Create)使用http://xxx/test/insert?name=y。

更新(Update)使用http://xxx/test/insert?name=y&content=z。

删除(Delete)使用http://xxx/test/delete?name=y。

二)單表多對象的CRUD操作

假設有這樣一種類關系:class b;為基類,class B1;和class B2;分别各自從class b;繼承,而B1和B2的對象存入資料庫時,都是存在一張表裡面,這種情況下,一張表的記錄record就可能轉換為B1和B2多種類的對象。

在資料庫中建立這樣一個表:

CREATE TABLE `b` (

  `name` varchar(255) NOT NULL,

  `content` varchar(255) DEFAULT NULL,

  `type` varchar(40) DEFAULT NULL,//type=='B1'代表是B1存儲而來,type=='B2'代表是B2存儲而來

  `contentB1` varchar(255) DEFAULT NULL,

  `contentB2` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`name`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    在Modules\Test\src\Model\下建立檔案“B.php”、“B1.php”、“B2.php”和“BTable.php”

B.php内容如下:

namespace Test\Model;

class B {
    
    public $name;
    public $content;
    public $type;
    
    public function __construct() {
    }

    public function exchangeArray($data) {
        $this->name = empty($data['name']) ? null : $data['name'];
        $this->content = empty($data['content']) ? null : $data['content'];
        $this->type = empty($data['type']) ? null : $data['type'];
    }
     
    public function getArrayCopy() {
        return get_object_vars($this);
    }
     
}
           

    B1.php内容如下:

namespace Test\Model;

use Test\Model\B;

class B1 extends B{
    
    public $contentB1;
    
    public function __construct() {
    }

    public function exchangeArray($data) {
        parent::exchangeArray($data);
        $this->contentB1 = empty($data['contentB1']) ? null : $data['contentB1'];
     }
     
    public function getArrayCopy() {
        return get_object_vars($this);
    }
}
           

    B2.php内容如下:

namespace Test\Model;

use Test\Model\B;

class B2 extends B{
    
    public $contentB2;
    
    public function __construct() {
    }

    public function exchangeArray($data) {
        parent::exchangeArray($data);
        $this->contentB2 = empty($data['contentB2']) ? null : $data['contentB2'];
     }
     
    public function getArrayCopy() {
        return get_object_vars($this);
    }
}
           

BTable.php内容如下:

namespace Test\Model;

use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Where;
use Zend\Db\Sql\Predicate\Operator;

use Test\Model\B;
use Test\Model\B1;
use Test\Model\B2;

class BTable {
    protected $tableGateway;
    
    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }
     
    public function select($where=null) {
        $resultSet = $this->tableGateway->select($where);
        //由于module.php裡面指定傳回的是關聯數組,是以此處要編寫關聯數組轉為對象數組的代碼
        $resultSetObjs = array();
        foreach ($resultSet as $rec) {
            $type = $rec['type'];
            if (empty($type)) {
                $obj = new B();
            } else if ($type == 'B1') {
                $obj = new B1();
            } else {
                $obj = new B2();
            }
            $obj->exchangeArray($rec);
            $resultSetObjs[] = $obj;
        }
        return $resultSetObjs;
    }
        
    public function update($b) {
        if (!($b instanceof B) &&
                !($b instanceof B1) &&
                !($b instanceof B2)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $b->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            $data = $b->getArrayCopy();
            unset($data['name']);//移除主鍵
            try {
                $ret = $this->tableGateway->update($data, array('name' => $b->name));
                if ($ret == 1 || $ret == 0) {
                    return true;
                }
            } catch (Exception $ex) {

            }
        }        
        return false;
    }
    
    public function insert($b) {
        if (!($b instanceof B) &&
                !($b instanceof B1) &&
                !($b instanceof B2)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $b->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            return false;
        }
        try {
            $data = $b->getArrayCopy();
            $ret = $this->tableGateway->insert($data);
            if ($ret == 1) {
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }     
     
    public function delete($b) {
        if (!($b instanceof B) &&
                !($b instanceof B1) &&
                !($b instanceof B2)) {
            return false;
        }
        try {
            $ret = $this->tableGateway->delete(array('name' => $b->name));
            if ($ret == 1) {
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }
}
           

打開Module\Test\Module.php檔案,修改getServiceConfig函數:

public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Test\Model\ATable' =>  function($sm) {
                    $tableGateway = $sm->get('ATableGateway');
                    $table = new ATable($tableGateway);
                    return $table;
                },
                'ATableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new A());
                    return new TableGateway('a', $dbAdapter, null, $resultSetPrototype);
                },
                'Test\Model\BTable' =>  function($sm) {
                    $tableGateway = $sm->get('BTableGateway');
                    $table = new BTable($tableGateway);
                    return $table;
                },
                'BTableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    //指定結果集是array,就可以阻止tableGateway将結果集的記錄映射成對象
                    //這是就需要在BTable的select函數裡手動将數組轉換為對象
                    $resultSetPrototype = new ResultSet(ResultSet::TYPE_ARRAY);
                    return new TableGateway('a', $dbAdapter, null, $resultSetPrototype);
                },
            ),
        );
    }
           

    其中new ResultSet(ResultSet::TYPE_ARRAY);TYPE_ARRAY的作用是讓ZendFramework2架構将結果集作為關聯數組傳回,之後就可以在BTable裡面通過代碼将記錄集轉換為不同對象了。

在Module\Test\src\Test\Controller\TestController.php中添加對象B、B1、B2的CRUD四個控制器:

class TestController extends AbstractActionController {
    
    protected $bTable;
    
    public function getBTable() {
        if (!$this->bTable) {
            $sm = $this->getServiceLocator();
            $this->bTable = $sm->get('Test\Model\BTable');
        }
        return $this->bTable;
    }

    public function selectbAction() {      
        $name = $this->params()->fromQuery('name');
        if (!empty($name)) {
            $where = new Where();
            $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $name));
        }
        
        $resultSet = $this->getBTable()->select((isset($where)?$where:null));   

        return new ViewModel(array(
            'bs' => $resultSet,
        ));
    }
    public function deletebAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        
        $b = new B;
        $b->name = $name;
        $ret = $this->getBTable()->delete($b);
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    public function updatebAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        $b = new B1;
        $b->name = $name;
        $b->content = 'new content';
        $b->type = 'B1';
        $b->contentB1 = 'B1';
        /*
        $b = new B2;
        $b->name = $name;
        $b->content = 'new content';
        $b->type = 'B2';
        $b->contentB2 = 'B2';
         */
        $ret = $this->getBTable()->update($b);
         
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    public function insertbAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        $b = new B2;
        $b->name = $name;
        $b->content = "b2 content";
        $b->type = 'B2';
        $b->contentB2 = 'B2';
        /*
        $b = new B2;
        $b->name = $name;
        $b->content = "b2 content";
        $b->type = 'B2';
        $b->contentB2 = 'B2';
         */
        $ret = $this->getATable()->insert($b);
        
        
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
}
           

同時記得添加引用:

use Test\Model\B;
use Test\Model\B1;
use Test\Model\B2;
           

最後在Module\Test\view\test\test\目錄下建立selectb.phtml、insertb.phtml、updateb.phtml和deleteb.phtml:

//selectb.phtml

 $title = 'selectB';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
    foreach ($this->bs as $b) {
        echo $this->escapeHtml($b->name);
        echo "------";
        echo $this->escapeHtml($b->content);
        echo "------";
        echo $this->escapeHtml($b->type);
        echo "------get_class:";
        echo $this->escapeHtml(get_class($b));
        echo "<br/>";
    }


//insertb.phtml

 $title = 'insertB';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


//updateb.phtml

 $title = 'updateB';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


//deleteb.phtml

 $title = 'deleteB';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";
           

讀取(Retrieve)使用http://xxxx/test/selectb或者http://xxx/test/selectb?name=y。

增加(Create)使用http://xxx/test/insertb?name=y。

更新(Update)使用http://xxx/test/insertb?name=y。

删除(Delete)使用http://xxx/test/deleteb?name=y。

三)多表單對象的CRUD操作

假設有這樣一種類關系:class Main;類中有個數組protected $path = array();将Main對象存入資料庫時,可能将$path單獨存入一張assisttable表,這樣情況下,多張表的多條記錄records才轉成類Main的一個對象。

    在資料庫中建立2張表:

CREATE TABLE `maintable` (

  `name` varchar(255) NOT NULL,

  `content` varchar(255) DEFAULT NULL,

  PRIMARY KEY (`name`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `assisttable` (

  `mainName` varchar(255) NOT NULL,

  `path` varchar(255) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

maintable表的name字段和assisttable的mainName字段是一對多的關系。

在Modules\Test\src\Model\下建立檔案“Main.php”、“MainTable.php”和“MaintableFeature.php“。

Main.php内容如下:

namespace Test\Model;

class Main {
    
    public $name;
    public $content;    
    public $path = array();
    
    public function __construct() {
    }
     
    public function getArrayCopy() {
        return get_object_vars($this);
    }
     
}
           

其中類Main沒有實作exchangeArray函數。

MainTable.php内容如下:

namespace Test\Model;

use Zend\Db\TableGateway\TableGateway;
use Zend\Db\Sql\Where;
use Zend\Db\Sql\Predicate\Operator;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Select;


use Test\Model\Main;

class MainTable {
    protected $tableGateway;
    
    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }
     
    public function select($where=null) {
        $selectFeature = new MaintableFeature('assisttable');
        $selectFeature->setParamsForSelect('maintable.name=assisttable.mainName');
        $this->tableGateway->getFeatureSet()->addFeature($selectFeature);
        $resultSet = $this->tableGateway->select($where);
        //将結果集轉換為對象數組
        $count = 1;
        $nameArray = array();
        $objectArray = array();
        foreach ($resultSet as $rec){
            $key = array_search($rec['name'], $nameArray);
            if (empty($key)) {
                $nameArray[$count] = $rec['name'];
                $objectArray[$count] = new Main();
                $objectArray[$count]->name = $rec['name'];
                $objectArray[$count]->content = (empty($rec['content'])?null:$rec['content']);
                if (!empty($rec['path'])) {
                    $objectArray[$count]->path[] = $rec['path'];
                }
                $count++;
            } else {
                if (!empty($rec['path'])) {
                    $objectArray[$key]->path[] = $rec['path'];
                }
            }
        }        
        return $objectArray;
    }
    
    public function insert($main) {
        if (!($main instanceof Main)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $main->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            return false;
        }
        try {
            $data = $main->getArrayCopy();
            //擷取要插入assisttable表的内容
            $dataAssist = array();
            foreach ($data['path'] as $path) {
                $dataAssist[] = array('mainName' => $data['name'], 'path' => $path);
            }
            $insertFeature = new MaintableFeature('assisttable');
            $insertFeature->setParamsForInsert($dataAssist);
            $this->tableGateway->getFeatureSet()->addFeature($insertFeature);
            unset($data['path']);//移除要寫入到assisttable的内容
            $ret = $this->tableGateway->insert($data);
            if ($ret == 1) {                
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }      
    
    public function delete($main) {
        if (!($main instanceof Main)) {
            return false;
        }
        try {
            $deleteFeature = new MaintableFeature('assisttable');
            $deleteFeature->setParamsForDelete($main->name);
            $this->tableGateway->getFeatureSet()->addFeature($deleteFeature);
            $ret = $this->tableGateway->delete(array('name' => $main->name));
            if ($ret == 1) {
                return true;
            }
        } catch (Exception $ex) {

        }
        return false;
    }

    public function update($main) {
        if (!($main instanceof Main)) {
            return false;
        }
        //檢查要修改的記錄主鍵是否存在
        $where = new Where();
        $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $main->name));
        $resultSet = $this->tableGateway->select($where);
        if (count($resultSet) > 0) {
            $data = $main->getArrayCopy();
            //擷取要插入assisttable表的内容
            $dataAssist = array();
            foreach ($data['path'] as $path) {
                $dataAssist[] = array('mainName' => $data['name'], 'path' => $path);
            }
            $updateFeature = new MaintableFeature('assisttable');
            $updateFeature->setParamsForUpdate($data['name'], $dataAssist);
            $this->tableGateway->getFeatureSet()->addFeature($updateFeature);
            unset($data['path']);//移除要寫入到assisttable的内容
            try {
                unset($data['name']);//移除主鍵
                $ret = $this->tableGateway->update($data, array('name' => $main->name));
                if ($ret == 1 || $ret == 0) {
                    return true;
                }
            } catch (Exception $ex) {

            }
        }        
        return false;
    }
}
           

MaintableFeature.php内容如下:

namespace Test\Model;

use Zend\Db\TableGateway\Feature\AbstractFeature;
use Zend\Db\Sql\Select;
use Zend\Db\Sql\Insert;
use Zend\Db\Sql\Delete;
use Zend\Db\Adapter\Driver\ResultInterface;
use Zend\Db\Adapter\Driver\StatementInterface;

class MaintableFeature extends AbstractFeature {

    protected $assistTable;//assistTable
    
    //select ref
    protected $onForSelect;
    protected $clumsForSelect;
    protected $methodForSelect;
    
    //insert ref
    protected $valsForInsert;
    
    //delete ref
    protected $mainNameForDelete;
    
    //update ref
    protected $valsForUpdate;
    protected $mainNameForUpdate;

    public function __construct($assistTable) {
        $this->assistTable = $assistTable;
    }

    public function setParamsForSelect($on, $clums=null, $method=null) {
        $this->onForSelect = $on;
        $this->clumsForSelect = $clums;
        $this->methodForSelect = $method;
    }
    public function preSelect(Select $select) {
         $select->join($this->assistTable, 
                 $this->onForSelect, 
                 empty($this->clumsForSelect)?Select::SQL_STAR:$this->clumsForSelect, 
                 empty($this->methodForSelect)?Select::JOIN_LEFT:$this->methodForSelect
                 ); 
    }
    
    public function setParamsForInsert($valsForInsert) {
        $this->valsForInsert = $valsForInsert;
    }
    public function postInsert(StatementInterface $statement, ResultInterface $result)
    {
        foreach ($this->valsForInsert as $vals) {
            $insert = new Insert($this->assistTable);
            $insert->values($vals);
            
            $statement = $this->tableGateway->getAdapter()->getDriver()->createStatement();        
            $insert->prepareStatement($this->tableGateway->getAdapter(), $statement);        
            $result = $statement->execute();
        }
    }
    
    public function setParamsForDelete($mainNameForDelete) {
        $this->mainNameForDelete = $mainNameForDelete;
    }
    public function postDelete(StatementInterface $statement, ResultInterface $result) {
        $delete = new Delete($this->assistTable);
        $delete->where(array('mainName' => $this->mainNameForDelete));

        $statement = $this->tableGateway->getAdapter()->getDriver()->createStatement();
        $delete->prepareStatement($this->tableGateway->getAdapter(), $statement);
        $result = $statement->execute();
    }
    
    public function setParamsForUpdate($mainNameForUpdate, $valsForUpdate) {
        $this->mainNameForUpdate = $mainNameForUpdate;
        $this->valsForUpdate = $valsForUpdate;
    }
    public function postUpdate(StatementInterface $statement, ResultInterface $result) {
        //delete asssist records first
        $delete = new Delete($this->assistTable);
        $delete->where(array('mainName' => $this->mainNameForUpdate));

        $statement = $this->tableGateway->getAdapter()->getDriver()->createStatement();
        $delete->prepareStatement($this->tableGateway->getAdapter(), $statement);
        $result = $statement->execute();
        
        //insert assist records next
        foreach ($this->valsForUpdate as $vals) {
            $insert = new Insert($this->assistTable);
            $insert->values($vals);
            
            $statement = $this->tableGateway->getAdapter()->getDriver()->createStatement();        
            $insert->prepareStatement($this->tableGateway->getAdapter(), $statement);        
            $result = $statement->execute();
        }
    }
}
           

MaintableFeature類主要實作tableGateway在執行select、update、delete和insert操作的時候,對關聯表assisttable也執行相應操作。

打開Module\Test\Module.php檔案,修改getServiceConfig函數:

public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'Test\Model\ATable' =>  function($sm) {
                    $tableGateway = $sm->get('ATableGateway');
                    $table = new ATable($tableGateway);
                    return $table;
                },
                'ATableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new A());
                    return new TableGateway('a', $dbAdapter, null, $resultSetPrototype);
                },
                'Test\Model\BTable' =>  function($sm) {
                    $tableGateway = $sm->get('BTableGateway');
                    $table = new BTable($tableGateway);
                    return $table;
                },
                'BTableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    //指定結果集是array,就可以阻止tableGateway将結果集的記錄映射成對象
                    //這是就需要在BTable的select函數裡手動将數組轉換為對象
                    $resultSetPrototype = new ResultSet(ResultSet::TYPE_ARRAY);
                    return new TableGateway('a', $dbAdapter, null, $resultSetPrototype);
                },
                'Test\Model\MainTable' =>  function($sm) {
                    $tableGateway = $sm->get('MainTableGateway');
                    $table = new MainTable($tableGateway);
                    return $table;
                },
                'MainTableGateway' => function ($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    //由于查詢到的結果集無法将assist表的記錄集按main表的主鍵聚合到Main對象内
                    //是以,此處還是阻止tableGateway将結果集的記錄映射成對象
                    //之後在MainTable的select函數裡手動将數組轉換為對象
                    $resultSetPrototype = new ResultSet(ResultSet::TYPE_ARRAY);
                    return new TableGateway('maintable', $dbAdapter, null, $resultSetPrototype);
                },
            ),
        );
    }
           

    在Module\Test\src\Test\Controller\TestController.php中添加對象Main的CRUD四個控制器:

class TestController extends AbstractActionController {
    
    protected $mainTable;
    
    public function getMainTable() {
        if (!$this->mainTable) {
            $sm = $this->getServiceLocator();
            $this->mainTable = $sm->get('Test\Model\MainTable');
        }
        return $this->mainTable;
    }

    public function selectmainAction() {      
        $name = $this->params()->fromQuery('name');
        if (!empty($name)) {
            $where = new Where();
            $where->addPredicate(new Operator('name', Operator::OPERATOR_EQUAL_TO, $name));
        }
        
        $resultSet = $this->getMainTable()->select((isset($where)?$where:null));   

        return new ViewModel(array(
            'mains' => $resultSet,
        ));
    }
    public function insertmainAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'main';
        }
        $main = new Main();
        $main->name = $name;
        $main->content = "main content";
        $main->path[] = 'path1';
        $main->path[] = 'path2';

        $ret = $this->getMainTable()->insert($main);       
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    public function deletemainAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        
        $main = new Main();
        $main->name = $name;
        $ret = $this->getMainTable()->delete($main);
        
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
    public function updatemainAction() {
        $name = $this->params()->fromQuery('name');
        if (empty($name)) {
            $name = 'name';
        }
        $main = new Main();
        $main->name = $name;
        $main->content = 'new content';
        $main->path = array();
        $main->path[] = 'patha';

        $ret = $this->getMainTable()->update($main);
         
        return new ViewModel(array(
            'ret' => ($ret==false?"false":"true"),
        ));
    }
}
           

同時記得添加引用:

use Test\Model\Main;
           

最後在Module\Test\view\test\test\目錄下建立selectmain.phtml、insertmain.phtml、updatemain.phtml和deletemain.phtml:

//selectmain.phtml

 $title = 'selectMain';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
    foreach ($this->mains as $main) {
        echo $this->escapeHtml($main->name);
        echo "------";
        echo $this->escapeHtml($main->content);
        echo "------";
        foreach ($main->path as $path) {
            echo $this->escapeHtml($path);
            echo "------";
        }
        echo "<br/>";
    }


//insertmain.phtml

 $title = 'insertMain';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


//updatemain.phtml

 $title = 'updateMain';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";


//deletemain.phtml

 $title = 'deleteMain';
 $this->headTitle($title);
 ?>
 <h1><?php echo $this->escapeHtml($title); ?></h1>

 <?php 
        echo $this->ret;
        echo "<br/>";
           

讀取(Retrieve)使用http://xxxx/test/selectmain或者http://xxx/test/selectmain?name=y。

增加(Create)使用http://xxx/test/insertmain?name=y。

更新(Update)使用http://xxx/test/insertmain?name=y。

删除(Delete)使用http://xxx/test/deletemain?name=y。