我试图实现memcache来存储Db结果(在tablegateway中),但我遇到了一个问题。如果没有"setItem"answers"getItem"方法,查询工作正常,但如果我使用它们,它会显示以下错误:
An error occurred
An error occurred during execution; please try again later.
Additional information:
PDOException
File:
C:'Program Files (x86)'xampp'htdocs'ZF-Tutorial'vendor'zendframework'zendframework'library'Zend'Serializer'Adapter'PhpSerialize.php:48
Message:
You cannot serialize or unserialize PDOStatement instances
在我的tablegateway里面有一个
namespace Application'Model;
use Zend'Cache'Storage'StorageInterface;
use Zend'Db'TableGateway'TableGateway;
use Zend'Db'Sql'Sql;
use Application'Model'Defaultlanguage;
class AccessoriesTable
{
protected $tableGateway;
protected $cache;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function setCache(StorageInterface $cache)
{
$this->cache = $cache;
}
public function fetchAll($lang = null)
{
if(!isset($lang)) {
$lang = DefaultLanguage::LANG;
}
if( ($result = $this->cache->getItem('testcache')) == FALSE) {
$adapter = $this->tableGateway->getAdapter();
$sql = new Sql($adapter);
$select = $sql->select();
$select->columns(array(
'id',
'accessories' => $lang
));
$select->from('cat_accessories');
$select->order('accessories ASC');
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$this->cache->setItem('testcache', $result);
}
return $result;
}
在我的模块内.php
'Application'Model'AccessoriesTable' => function($sm) {
$tableGateway = $sm->get('AccessoriesTableGateway');
$cacheAdapter = $sm->get('Zend'Cache'Storage'Memcache');
$table = new AccessoriesTable($tableGateway);
$table->setCache($cacheAdapter);
return $table;
},
'AccessoriesTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend'Db'Adapter'Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Accessories());
return new TableGateway('cat_accessories', $dbAdapter, null, $resultSetPrototype);
},
我试着在我的控制器和视图中使用memcache,效果很好。我不明白错误在哪里。谢谢大家的帮助。
2015年6月28日版
我在这里找到了一个解决方案,效果很好,但我不太喜欢:https://samsonasik.wordpress.com/2012/09/27/zend-framework-2-using-zendcache-and-hydratingresultset-to-save-database-resultset/
内部模块.php
'Application'Model'AccessoriesTable' => function($sm) {
$dbAdapter = $sm->get('Zend'Db'Adapter'Adapter');
$cacheAdapter = $sm->get('Zend'Cache'Storage'Memcache');
$table = new AccessoriesTable($dbAdapter);
$table->setCache($cacheAdapter);
return $table;
},
内部配件类别:
namespace Application'Model;
class Accessories
{
public $id;
public $accessories;
public function exchangeArray($data)
{
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->accessories = (!empty($data['accessories'])) ? $data['accessories'] : null;
}
public function getArrayCopy()
{
return get_object_vars($this);
}
}
内部附件表:
namespace Application'Model;
use Zend'Db'Adapter'Adapter;
use Zend'Db'ResultSet'HydratingResultSet;
use Zend'Db'TableGateway'AbstractTableGateway;
use Zend'Db'Sql'Select;
use Zend'Cache'Storage'StorageInterface;
use Application'Model'Accessories;
use Application'Model'Defaultlanguage;
class AccessoriesTable extends AbstractTableGateway
{
protected $table = 'cat_accessories';
protected $cache;
public $lang;
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new HydratingResultSet();
$this->resultSetPrototype->setObjectPrototype(new Accessories());
$this->initialize();
}
public function fetchAll($lang = null)
{
$this->setLang($lang);
$cacheName = md5('accessories-'.$this->lang);
if( ($resultSet = $this->cache->getItem($cacheName)) == FALSE) {
$resultSet = $this->select(function (Select $select){
$select->columns(array('id', 'accessories'=> $this->lang ));
$select->order(array($this->lang. ' asc'));
});
$this->cache->setItem($cacheName , $resultSet );
}
return $resultSet;
}
}
新问题:如何使用"传统"表网关结构实现它????
我尝试使用传统的表网关,但错误与上面相同。
内部表网关:
public function fetchAll($lang = null)
{
$this->setLang($lang);
$cacheName = md5('accessories-'.$this->lang);
if( ($resultSet = $this->cache->getItem($cacheName)) == FALSE) {
$resultSet = $this->tableGateway->select(function (Select $select){
$select->columns(array('id', 'accessories'=> $this->lang ));
$select->order(array($this->lang. ' asc'));
});
$this->cache->setItem($cacheName , $resultSet );
}
return $resultSet;
}
第一条错误消息中明确指出的主要问题;您正在尝试保存一个PDOStatement
实例,该实例是execute()
方法的输出。然后,您的缓存后端会自动尝试序列化那个实际上不可序列化的语句实例。
$result = $statement->execute();
$this->cache->setItem('testcache', $result);
只需从resultset中获取数据并对其进行迭代。在迭代时将数据转换为数组,或者如果项是对象,则通过实现ArraySerializableInterface向该对象添加getArrayCopy()
方法,从而轻松提取对象的数组副本并存储到缓存中。
对于大多数场景,用getArrayCopy()
方法返回一个简单的关联数组就足够了,例如:
public function getArrayCopy()
{
return [
'id' => $this->id,
'name' => $this->name,
'bar' => $this->bar,
'baz' => $this->baz,
];
}
这些是错误:
$result = $statement->execute();
$this->cache->setItem('testcache', $result);
$result变量是一个ResultSet对象,您正试图将其插入memcached(整个对象,而不仅仅是返回数据)中。试着做这个$result->current();
,让我知道发生了什么。
编辑:2015年6月28日
由于我给你的链接将在一周后过期,我决定将代码包含在中
/**
* Create plain mysql queries.
*
* @param String $sql the plain query
* @throws Exception If database is not found or $sql is empty
* @return array|HydratingResultSet|null
*/
use Zend'Db'Adapter'Adapter;
use Zend'Db'ResultSet'HydratingResultSet;
use Zend'Stdlib'Hydrator'ObjectProperty;
use Zend'Db'Adapter'Driver'Pdo'Result;
public static function createPlainQuery($sql = null)
{
$dir = dirname(dirname(dirname(__DIR__)));
if (!is_file($dir.'/config/autoload/local.php')) {
throw new 'Exception("Could not load database settings");
}
if (empty($sql)) {
throw new 'Exception(__METHOD__ . ' must not be empty');
}
$local = require($dir.'/config/autoload/local.php');
$db = new Adapter($local['db']);
$stmt = $db->createStatement((string) $sql);
$stmt->prepare();
$result = $stmt->execute();
if ($result instanceof Result && $result->isQueryResult() && $result->getAffectedRows()) {
$resultSet = new HydratingResultSet(new ObjectProperty(), new 'stdClass());
$resultSet->initialize($result);
$resultSet->buffer();
return ($resultSet->valid() && $resultSet->count() > 0 ? $resultSet->toArray() : null);
}
return null;
}