То, о чем я расскажу под катом:
- Открытие одной и той же странички: через ajax-запрос (без layout) и обычное открытие странички вместе с layout
- Кеширование моделей без кода в каждой модели
- Как сделать логирование логики с минимальным кодом
- Как обернуть всё в транзакции с минимальным кодом
- Как сделать так, чтобы на каждом сервере (с экземпляром приложения) не менять файл основного конфига приложения. Упрощаем деплой
Открытие одной и той же странички: через ajax-запрос и обычное открытие странички с layout
Описание: Очень полезно бывает уметь открывать одну и ту же страницу (одна и таже view + action) и как фрагмент страницы запрошенный через ajax ( $.load() ) и как цельную страницу вместе с layout.
Пример применения: Табы на bootstrap с реализацией через ajax. Они сделаны в виде <li><a></a></li> — соответственно их можно «открыть в новом окне» — тут будет полезно уметь отдать страничку вместе с layout.
Код:
# protected/components/LController.php class LController extends CController { public function init() { parent::init(); if (Yii::app()->request->getIsAjaxRequest()) { $this->layout = '//layouts/clear'; } } } # themes/classic/views/layouts/clear.php: <?= $content ?> # в контроллерах, где это нужно, наследуемся от LController: class DefaultController extends LController { …. }
Кеширование моделей без кода в каждой модели
Описание: Все мы (разработчики под Yii) в какой то степени используем findByPk и довольно сильно нагружаем базу запросами. Пусть они и по Primary Key, но сам факт запроса неприятен. Здесь я покажу как в Yii раз и навсегда засунуть модель в кеш без лишнего кода в самих моделях
Применение: Любое приложение, где требуется кеширование. При условии, что вся работа с базой делается только через ActiveRecord и изменения производятся только через методы save() и delete() экземпляра модели.
Код:
# protected/components/LActiveRecord.php class LActiveRecord extends CActiveRecord { public static function getByPk($pk){ $cache = Yii::app()->cache->get(‘activerecord.’.self::$clss.’.’.$pk); if ($cache) $cache = unserialize($cache); if ($cache) return $cache; $clss = self::$class $entity = $clss::model()->findByPk($pk); Yii::app()->cache->set(‘activerecord.’.self::$clss.’.’.$pk,serialize($entity)); } public function save($runValidation = true, $attributes = NULL){ $result = parent::save($runValidation, $attributes); $self = get_class($this); Yii::app()->cache->set(‘activerecord.’.$self::$clss.’.’.$pk, serialize($this)); return $result; } public function delete() { $self = get_class($this); $ret = parent::delete(); Yii::app()->cache->delete(‘activerecord.’.$self::$clss.’.’.$pk); return $ret; } } #все модели наследуем от LActiveRecord: class User extends LActiveRecord { public final static $clss = “User”; //прописываем имя класса для дальнейших обращений (были в классе-родителе) ... } #все выборки по Primary Key делаем так: $user = User::getByPk(1);
Логирование логики
Описание: Иногда полезно писать логи действий с моделями — что, когда, с чем. Полезно и для отладки и для анализа популярности функционала и для анализа производительности.
Применение: почти везде где требуется вышесказанное
Код:
В указанный выше класс LActiveRecord добавляем следующее:
# в метод save (на место старого parent::save): $ts = microtime(true); if ($this->isNewRecord) { $action = 'create/' . $this->id; } else { $action = 'update/' . $this->id; } $result = parent::save($runValidation, $attributes); $ts = microtime(true)-$ts; $this->logMe($action.’ time: ’.ts); # в метод delete (на место старого parent::delete): $ts = microtime(true); $ret = parent::delete(); $ts = microtime(true)-$ts; $this->logMe('delete/' . $this->id.’ time:’.$ts); #и добавляем метод logMe: private function logMe($action){ $model_log = Yii::app()->params['model_log_file']; $table = $this->tableName(); $str = date('[Y-m-d H:i:s]') . ' [' . $table . '] ' . ' ' . $action . "\r\n"; error_log($str, 3, $model_log); } #в наши params добавляем параметр с именем файла для лога: ‘'model_log_file’ => ‘/var/www/application/logs/model.log’;
И снова все наши модели должны быть унаследованы от LActiveRecord.
Как обернуть всё в транзакции с минимальным кодом
Описание: Мне довольно часто нужно сделать так, чтобы все действия с базой были транзакционными, чтобы не писать код начала и конца транзакции везде, я вынес его в один метод, который yii вызывает автоматически.
Применение: везде где страшно получить кашу в базе
Код:
В указанный выше LController добавляем метод:
public function run($actionID) { //начинается всё с копипасты из ядра yii: if(($action=$this->createAction($actionID))!==null) { if(($parent=$this->getModule())===null) $parent=Yii::app(); if($parent->beforeControllerAction($this,$action)) { //здесь начинается код отличный от кода yii, в нем мы запускаем транзакцию: try { $transaction=Yii::app()->db->beginTransaction(); $this->runActionWithFilters($action,$this->filters()); //запускаем экшин $transaction->commit(); //всё ок } catch (Exception $e){ $transaction->rollback(); //всё упало throw $e; } //продолжается всё стандарным кодом yii: $parent->afterControllerAction($this,$action); } } else $this->missingAction($actionID); } #соответственно все контроллеры, где должны быть транзакции надо унаследовать от LController
Метод run в контроллере yii вызывает каждый раз, когда запускает контроллер, он реализован в классе CController. Нам повезло с тем, что он публичный и мы можем его переопределить. Из-за переопределения приходится частично возвращать в него код Yii, но в этом переопределении ничего плохого нет — этот код стабилен и уже работает.
Как сделать так, что бы не менять на каждом сервере с экземпляром приложения файл основного конфига. Упрощаем деплой
Описание: У нас есть задача — деплой кода на N серверов с помощью git pull. При этом у нас могут добавлятся строки в конфиг (с появлением новых модулей и прочего). Явно не хочется каждый раз руками выправлять адрес базы, memcached, других локальных настроек.
Применение: Везде где приложение развернуто в нескольких местах с разными настройками, хоть у 2х девелоперов и на продакшине.
Код:
#/protected/config/main.php #в самом начале файла добавляем строку: $local_config = require(dirname(__FILE__).’/local.php’); #/protected/config/local.php: return array( ‘db’ => array( //копируем сюда строки с настройкой нашей БД, 'connectionString', 'username', ‘password’ ), ‘memcache_servers’ => array( array('host'=>'127.0.0.1', 'port'=>11211, 'weight'=>60), //ваши настройки memcached ) ) # в /protected/config/main.php делаем изменения: # 1. находим ключ ‘db’ и делаем его таким: 'db'=>$local_config[‘db’]; # 2. находим ключ ‘servers’ внутри массива ‘cache’ и делаем его таким: 'servers'=>$local_config[‘memcache_servers’]
потом добавляем в .gitignore файл local.php. Перед деплоем не забываем на каждом сервере создать этот файл и внести локальные настройки.
Это всё работает и используется?
Да все эти методы уже используются в проекте note-space.com уже больше года. Работает это на Yii 1.1.8, возможно еще более новых версиях, возможно нет — но это не мешает Вам адаптировать код под Вашу версию фреймворка.
P.S. Если Вы будете использовать этот код и возникнут проблемы, то можно смело обращаться за поддержкой прямо ко мне — всегда рад помочь и сделать код лучше.
ссылка на оригинал статьи http://habrahabr.ru/post/157769/
Добавить комментарий