2015-06-26 2 views
2

Я попытался реализовать memcache для хранения результатов Db (в пределах tablegateway), но у меня есть проблема. Без «SetItem» и методы «GetItem», запрос работает отлично, но если я использую их, он выводит сообщение об ошибке:Zend Framework 2 - Использование Memcache/Memcached для хранения результатов DB

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 внутри своего контроллера и просматривать и работать нормально. Я не понимаю, где (есть) ошибка (ы). Спасибо всем вам за помощь.

EDIT 28-06-2015

Я нашел решение здесь, работает нормально, но я не люблю так много: https://samsonasik.wordpress.com/2012/09/27/zend-framework-2-using-zendcache-and-hydratingresultset-to-save-database-resultset/

внутри module.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); 
    } 
} 

Внутри AccessoriesTable:

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; 
    } 
} 

НОВЫЙ ВОПРОС: как я могу реализовать его с "традиционным" tablegateway конструкции ????

Я попытался использовать традиционный tablegateway, но ошибка такая же.

внутри tablegateway:

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; 
} 

ответ

0

Эти ошибки:

$result = $statement->execute(); 
$this->cache->setItem('testcache', $result); 

Ваши переменный $ результата является ResultSet объект, который вы пытаетесь вставить в Memcached (весь объект, а не его возвращать данные). Попробуйте сделать это $result->current(); и дайте мне знать, что произошло.

EDIT: 28.06.2015

Поскольку связь я дал вам истекает через неделю, я решил включить код в

/** 
* 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; 
} 
+0

Works! но current() возвращает только строку результатов запроса. –

+0

Хорошо, так. Попробуйте вызвать $ result-> toArray(), но я предполагаю, что это вызовет исключение. Другой способ - просто перебрать это с помощью цикла foreach. foreach ($ result as $ key => $ res) {$ this-> cache-> setItem ('testcache', $ res); } ' Кроме того, это моя собственная реализация простой функции запроса mysql. С помощью этой функции вы получите простой результат массива (просто массив, а не массивный объект или что-то еще), который вы можете напрямую вставить в свой memcache. http://paste.ofcode.org/ujWdDnkm6FmQ5b6GHBQYJB – Stanimir

+0

посмотреть новое редактирование, I нашел решение, но мне не очень нравится –

0

Основная проблема, которая четко отмечено в первой ошибки сообщение; вы пытаетесь сохранить экземпляр PDOStatement, который является результатом метода execute(). Затем ваш сервер кэширования автоматически пытается сериализовать этот экземпляр оператора, который на самом деле не является сериализуемым.

$result = $statement->execute(); 
$this->cache->setItem('testcache', $result); 

Просто получите данные из набора результатов и перейдите по нему.Преобразуйте данные в массив во время итерации или если объекты являются объектами, затем добавьте метод getArrayCopy() к этим объектам, реализовав ArraySerializableInterface, чтобы легко извлечь копию массива объекта и сохранить его в кеш.

Возвращаясь простой ассоциативный массив в getArrayCopy() метод будет достаточно для большинства сценариев, например:

public function getArrayCopy() 
{ 
    return [ 
     'id' => $this->id, 
     'name' => $this->name, 
     'bar' => $this->bar, 
     'baz' => $this->baz, 
    ]; 
} 
+0

У меня есть метод getArrayCopy внутри класса Accessories. Посмотрите новое редактирование, я нашел решение здесь: https://samsonasik.wordpress.com/2012/09/27/zend-framework-2-using-zendcache-and-hydratingresultset-to-save-database-resultset/ , но мне не нравится конструкция таблицы. Как я могу реализовать с помощью «традиционной» конструкции tablegateway? –

Смежные вопросы