Memcached + Doctrine + Zend Framework
Совмещаем все это вместе, получаем неплохое ускорение работы доктрины.
Ставим memcached
Как Установить Memcached на windows?
- качаем отсюда бинарник http://code.jellycan.com/memcached/
- ложим в c:\memcached (или другой путь)
- из консоли инсталим как сервис c:\memcached\memcached.exe -d install
Установка под *nix ищется на ура в гугли.
bootstrap
(привожу весь код инитера доктрины)
/* * Init Doctrine */ protected function _initDoctrine() { $config=$this->getOption('database'); require_once 'Doctrine.php'; $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader->registerNamespace('Doctrine'); try { Doctrine_Manager::connection("mysql://".$config['params']['username'].":".$config['params']['password']."@".$config['params']['host']."/".$config['params']['dbname'])->setCharset($config['charset']); } catch (Exception $e) { echo 'FATAL ERROR: MySql is down'; exit; } Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_AGGRESSIVE); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM, true); Doctrine::loadModels(APPLICATION_ROOT . "/models"); // Install Tables Doctrine::createTablesFromModels(APPLICATION_ROOT . "/models"); // Cache $configCache=$this->getOption('cache'); // Clearer -------------------------------------------------------- $memcache_obj = new Memcache; $con=$memcache_obj->connect($configCache['host'], $configCache['port']); if ($con==FALSE) { echo 'FATAL ERROR: MemCache is down'; exit; } //$memcache_obj->flush(); // отчистка кеша // --------------------------------------------------------------- $servers = array( 'host' => $configCache['host'], 'port' => $configCache['port'], 'persistent' => true ); $cacheDriver = new Doctrine_Cache_Memcache(array( 'servers' => $servers, 'compression' => false ) ); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_QUERY_CACHE_LIFESPAN, 3600); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_RESULT_CACHE_LIFESPAN, 3600); }
Все проинииализили и сказали Doctrine что нужно использовать memcache при запросах и выдачи результата
Если у вас в проекте есть Zend_Translate то подцепляем и его:
$configCache=$this->getOption('cache'); $backendOptions=array( 'host' => $configCache['host'], 'port' => $configCache['port'], 'persistent' => true ); $cache = Zend_Cache::factory('Core', 'Memcached', $frontendOptions, $backendOptions); Zend_Translate::setCache($cache);
везде используются данные из конфига (ini) вот кусок:
; cache memcached cache.host = localhost cache.port = 11211
Запросы
1. После тестов, прямые запросы (DQL) выполняются намного шустрей, т.е.:
$q = Doctrine_Query::create() ->select('id, url') ->from('NewsCategories'); $newsCategories= $q->execute()->toKeyValueArray("id","url");
Намного шустрей чем удобное
$newsCategories=Doctrine::getTable("NewsCategories")->findAll()->toKeyValueArray("id","url");
и плюс, в последнем запросе нельзя указывать что нужно использовать кеш (!!!)
теперь все свои запросы приводим в вид «юзай кеш»
$q = Doctrine_Query::create() ->select('id, url') ->from('NewsCategories') ->useCache(); $newsCategories= $q->execute()->toKeyValueArray("id","url");
все =)
Уникальных посетителей темы: 189Doctrine Accessors и Mutators
Очень часто пароль мы хешируем, для этого есть замечательный метод hasMutator.
Пример модели:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class User extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('username', 'string' 255); $this->hasColumn('password', 'string', 255); } public function setUp() { $this->hasMutator('password', 'md5Password'); } public function md5Password($value) { $this->_set('password', md5($value)); } } |
и теперь когда мы работаем с созданием модели, апдейтом и т.д. можно просто писать так
1 2 3 4 | $user=new Users(); $user->username="aa"; $user->password="haha"; $user->save(); |
в базе будет положена колонка с паролем в md5
Уникальных посетителей темы: 46Doctrine & Zend Framework 1.8 (zf1.8)
В ветке 1.8 были изменены методы инициалиции, в частности все вынесенно в Bootstrap.php. Теперь о том как подключить Doctrine к ZF 1.8.4.
В конфиге (application/configs/application.ini) :
1 2 3 4 5 6 | database.adapter = PDO_MYSQL database.params.host = localhost database.params.username = dbloging database.params.password = dbpass database.params.dbname = dbname database.charset = utf8 |
В application/Bootstrap.php добавляем :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | protected function _initDoctrine() { $config=$this->getOption('database'); require_once 'Doctrine.php'; $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader->registerNamespace('Doctrine'); Doctrine_Manager::connection("mysql://".$config['params']['username'].":".$config['params']['password']."@".$config['params']['host']."/".$config['params']['dbname'])->setCharset($config['charset']); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_AGGRESSIVE); Doctrine_Manager::getInstance()->setAttribute(Doctrine::ATTR_USE_NATIVE_ENUM, true); Doctrine::loadModels(APPLICATION_PATH . "/models"); } |
Уникальных посетителей темы: 51Обновления Zend Framework 1.8.1 и Doctrine 1.1.1
Обновляемся на новые версии фреймворка и doctrine.
Zend Framework качаем тут:
http://framework.zend.com/download/latest
обзор прошлой версии смотрим тут
http://devzone.zend.com/article/4524-Zend-Framework-1.8.0-Released
В данной версии исправленно более 68 ошибок в коде, ошибки в документации и «Быстром старте». Так же сделанны изменения (без перевода)
- Zend_Loader::registerAutoload() now proxies to Zend_Loader_Autoloader, and marks the instance as a fallback autoloader. This will ensure equivalent functionality, and reduces the number of deprecation notices emitted to one.
- Many bugfixes and improvements to Zend_Application.
- Addition of module generation capabilities to Zend_Tool
- Addition of strong object typing capabilities to Zend_Amf
- Many more manual translations!
Полный список тут: http://short.ie/zf1-8-1-issues
Doctrine
Качаем как обычно с http://www.doctrine-project.org/download
Уникальных посетителей темы: 21Doctrine 1.1 Released !
Сегодня была зарелизина Doctrine 1.1 !
Новшества:
* Новый hydration метод
* Новый иструмент для «объединений» миграций
* Улучшена поддержка и интеграция для accessor и mutator в fromArray() и toArray()
* Усовершенствования в getModified(), toArray(), fromArray(), synchronizeWithArray()
* Усовершенствования ядро для поиска, SoftDelete, Versionable
* и т.д.
Более подробную информацию о новшествах можно прочитать тут http://www.doctrine-project.org/upgrade/1_1
или обновляем по svn:
$ svn co http://svn.doctrine-project.org/tags/1.1.0/lib doctrine
upd: Нашел удобную для себя функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | $q = Doctrine_Query::create() ->from('User u'); $users = $q->execute(); $array = $users->toKeyValueArray('id', 'name'); print_r($array); /* array( 4 => 'zYne', 5 => 'Arnold Schwarzenegger', 6 => 'Michael Caine', 7 => 'Takeshi Kitano', 8 => 'Sylvester Stallone', 9 => 'Kurt Russell', 10 => 'Jean Reno', 11 => 'Edward Furlong', ) */ |
Что есть очень удобно для передачи потом виеву для формирование полей значений для select!
Уникальных посетителей темы: 15Doctrine Profiler
Иногда полезно видеть какие запросы строит Doctrine и сколько времени они выполняются. Описание профайлера в оригинале тут: http://www.doctrine-project.org/documentation/manual/1_1/en/component-overview#profiler
Ниже мой пример.
1. В Initializer.php
public function initDb() { ... $profiler = new Doctrine_Connection_Profiler (); Doctrine_Manager::getInstance()->setListener($profiler); Zend_Registry::set('dbProfiler', $profiler); ...
2. В bootstrap.php
... //В конце файла $profiler=Zend_Registry::get('dbProfiler'); echo "<div class=box style=\"font-family: Courier New; font-size: 11px\">"; $time = 0; foreach ( $profiler as $event ) { $time += $event -> getElapsedSecs (); echo "<b><font color=red>".$event ->getName () . "</font></b> [" . sprintf ("%f", $event -> getElapsedSecs ()) . "]<br>\n"; echo $event ->getQuery () . "<br>\n"; $params = $event ->getParams (); if( ! empty ( $params )) { var_dump ( $params ); echo "<br>"; } } echo "<br><b>Total time : " . $time . "</b><br>\n"; echo "</div>"; ...
В итоге при каждом генерировании страницы, внизу, мы увидем профайл doctrine, к примеру вот так:
query [0.001810] SELECT l.id AS l__id, l.date AS l__date, l.username AS l__username, l.ip AS l__ip, l.text AS l__text, l.created_at AS l__created_at, l.updated_at AS l__updated_at FROM logs l ORDER BY l.date DESC LIMIT 20 prepare [0.000102] SELECT u.id AS u__id, u.status AS u__status, u.role AS u__role, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.im AS u__im, u.lastlogin AS u__lastlogin, u.ballance AS u__ballance, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM users u WHERE u.id = ? LIMIT 1 execute [0.002061] SELECT u.id AS u__id, u.status AS u__status, u.role AS u__role, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.im AS u__im, u.lastlogin AS u__lastlogin, u.ballance AS u__ballance, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM users u WHERE u.id = ? LIMIT 1 array(1) { [0]=> string(1) "1" } fetch [0.000094] SELECT u.id AS u__id, u.status AS u__status, u.role AS u__role, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.im AS u__im, u.lastlogin AS u__lastlogin, u.ballance AS u__ballance, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM users u WHERE u.id = ? LIMIT 1 fetch [0.000075] SELECT u.id AS u__id, u.status AS u__status, u.role AS u__role, u.username AS u__username, u.password AS u__password, u.email AS u__email, u.im AS u__im, u.lastlogin AS u__lastlogin, u.ballance AS u__ballance, u.created_at AS u__created_at, u.updated_at AS u__updated_at FROM users u WHERE u.id = ? LIMIT 1 Total time : 0.00414180755615
Уникальных посетителей темы: 63Doctrine Pagination – Постраничная разбивка средствами Doctrine
В ZendFramework конечно есть модуль Pagination, но после его использования я решил поглядеть а что есть у Doctrine и нужно сказать что у нее это ЕСТЬ и реализованно неплохо!
Оригинальное описание находится тут: http://www.doctrine-project.org/documentation/manual/1_0/en/utilities#pagination
Пример использования:
1. В контроллере пишем:
$currentPage=$this->_getParam("pager"); // Номер страницы из роутера $resultsPerPage=20; // Cколько результатор на одной странице $pager_layout = new Doctrine_Pager_Layout ( new Doctrine_Pager ( Doctrine_Query :: create () ->from ( "Users u" ) ->orderBy ( "id DESC" ), $currentPage , $resultsPerPage ), new Doctrine_Pager_Range_Sliding ( array ( "chunk" => 5 )), "/admin/users/index/{%page_number}" ); $pager_layout ->setTemplate ('<a href="{%url}" class="pager">{%page}</a> '); $pager_layout ->setSelectedTemplate ('<b class="pager">{%page}</b> '); $pager = $pager_layout ->getPager (); $users = $pager->execute(); $this->view->pager = "Page: ".$pager_layout ->display('',true)." Total items: <b>".$pager->getNumResults()."</b>";
2. В роутере пропишем:
$router->addRoute('amdinUsers', new Zend_Controller_Router_Route('admin/users/index/:pager', array('module' => 'admin', 'controller' => 'users', 'action' => 'index', 'pager' => '1') ));
3. В виеве соответственно ловим:
<div class="pager_box"><?php echo $this->pager ?></div>
Уникальных посетителей темы: 172Doctrine ORM for PHP Новая документация
Вчера была выложена новая, переработанная документация по Doctrine, имя ей «Doctrine ORM for PHP». Вся документация была переписана, исправлена и добавлена и доступна по адресу: http://www.doctrine-project.org/documentation/manual/1_0/en
Уникальных посетителей темы: 250Doctrine – Двойная доза
Вышло сразу два обновления, обновились до версий 1.0.5 и бета 1.1. Смотреть и качать тут.
Уникальных посетителей темы: 43Doctrine & ZF Cheat Sheet
Тут я приведу несколько часто используемых мной приемов для работы с Doctrine и (или) ZF.
1. Выбока по id с проверкой на существование записи:
$courier = Doctrine::getTable("Couriers")->find($this->_getParam('id')); if ($courier===FALSE) throw new Exception("courierId не найден"); $this->view->courier=$courier->toArray();
Теперь по строкам:
- Выбираем из модели Couriers запись с id который нам передал Zend Framework через Router в параметр id.
- Если запись не найденна но генерим новое исключение.
- Передаем «виеву» массив данных от записи.
2. Сбор все related записей у модели
Как неидеальный пример:
$query = new Doctrine_Query(); $query->from('CityAddress ca,ca.CityStreets cs,cs.CityRegions cr') >where("id=?",intval($id) ); $result = $query->execute( array(),Doctrine::HYDRATE_ARRAY );
Что вернет нам не только запись но и все «привязанные» записи (hasOne, hasMany)
3. NOW()
Вернуть текущее время и дату
$messages->date_delivery=new Doctrine_Expression('NOW()');
4. Last Insert ID
Вернуть последний добавленный ID записи
$lastInsertedId=$model->getIncremented();
Уникальных посетителей темы: 98