Давно я не брал в руки шашек. То есть не писал про symfony. А разработка продолжается. Сайт фактически готов, остаются мелкие доделки, доработка напильником и все такое. О "переключателях" или "тогглерах"(togglers), или не знаю как еще их назвать я уже давно хотел написать. Ну вот и пришло время, получайте.
Итак что же за переключатели такие? Допустим у нас есть сайт, а у него база данных, а в базе данных таблица, а в таблице поле, которое принимает только 2 значения - 0 и 1. Такие поля делаются типа TINYINT(1). Берем пример из жизни. Одно такое поле отвечает за то, разрешено ли пользователю входить в систему или нет. И если вдруг надо нам попереключать часть пользователей, то надо залезать в свойства каждого и менять, потом сохранять. А мне захотелось жить красивее и придумал я переключатели.

Вот так примерно выглядит список пользователей. Зеленая галочка и красный крестик и есть переключатели. Что сделать чтобы переключить пользователя? Просто кликнуть на них! По клику отправляется AJAX запрос, меняет поле в базе данных и по результатам меняет картинку. Красиво, удобно, быстро. А теперь о том, как это сделано.
Для каждого пользователя в таблице нам надо вставить партиал (partial), который будет отображать картинку. Для формирования таблицы мы foreach перебираем пользователей и вот код partial для переключателя.
<div id="active_<?php echo $user['id']; ?>"> <?php include_partial('activity', array('id' => $user['id'], 'state' => $user['is_active']))?> </div>
Как видно в него мы передаем 2 параметра, это id пользователя и его текущий статус. В самом партиалле находится следующий код:
<?php $field = 'IsActive'; ?> <div align="center" id="<?php echo $field.'_'.$id ?>"> <?php include_component('main', 'toggler', array( 'id' => $id, 'table' => 'sfGuardUser', 'state' => sfGuardUserPeer::retrieveByPK($id)->getIsActive(), 'field' => $field )); ?> </div>
Здесь $field - имя поля в базе данных. В партиалле создается div с названием $field_$id, куда будет присылаться ответ. Ну а дальше вызывается компонент main/toggler, который и будет собственно переключать. Компоненту мы передаем id пользователя, имя таблицы, текущее состояние и имя поля.
На этом подключение переключателя к модулю завершено. То есть вам надо всего лишь вызвать partial из шаблона, а в partiall'e подправить названия поля и таблицы. Все очень просто и быстро. Ну а собственно что в компоненте main/toggler? А там вот что:
components.class.php
public function executeToggler() { //i just call _toggler.php partial }
_toggler.php
<?php $update = $field.'_'.$id; sfApplicationConfiguration::getActive()->loadHelpers(array('Javascript')); $image_name = intval($state)? 'active.png' : 'inactive.png'; echo link_to_remote(image_tag('/images/icons/admin/'.$image_name), array ( 'url' => 'main/toggle?id='.$id.'&table='.$table.'&field='.$field, 'update' => $update )); ?>
Мы формируем $update - поле, куда вернем ответ. А в виде ответа мы возвращаем... переключатель. Нам надо подгрузить хелпер Javascript (обратите внимание, что надо с большой буквы писать, иначе ничего не получится. симфони требует соблюдения регистра). И с помощью хелпера генерим аяксовую ссылку на экшен, который уже и будет переключать.
Что же получается? Итак общая картинка такая. Мы подключаем partial, который вызывает компонент, который генерит шаблон выдавая нам аяксовую ссылку на действие (action). А экшен переключает нам поле, и рендерит тот же самый компонент.
public function executeToggle(sfWebRequest $request) { if (!$request->isXmlHttpRequest()) { return $this->renderText('Error. XMLHttpRequests only.'); } $id = $request->getParameter('id'); $table = $request->getParameter('table'); $field = $request->getParameter('field'); $peer = $this->normalizeName($table).'Peer'; $method = new ReflectionMethod($peer, 'retrieveByPK'); $object = $method->invoke(NULL, $id); $setter = 'set'.ucfirst(strtolower($field)); $getter = 'get'.ucfirst(strtolower($field)); $object->$setter( $state = !$object->$getter() )->save(); return $this->renderPartial('main/toggler', array('id' => $id, 'state' => $state, 'table' => $table, 'field' => $field)); } protected function normalizeName($name) { $name = preg_replace('/[^a-zA-Z0-9]/', ' ', $name); $name = ucwords(strtolower($name)); $name = str_replace(' ', '', $name); return $name; }
Принимаем только аяксовые запросы, из запроса получаем таблицу, поле и имя Propel Peer-класса для управления таблицей. Имя таблицы мы "нормализуем", т.к. симфони не использует, например, подчеркиваний в названии Peer-классов. Ну а дальше, с помощью рефлексии мы вызываем метод для того, чтобы получить объект, над которым производим действия. Геттеры и сеттер имеют стандартные названия и их рефлексить нам не надо. После чего в ответ рендерим тот же самый компонент, который вернет нам картинку с аяксовой ссылкой на то же самое действие.
Я догадываюсь, что это не так просто понять. Если будет совсем не в моготу - задавайте вопросы в комментариях.
А еще я писал про:










Май 26th, 2009 at 20:42
не подскажешь как использовать pear библиотеки в симфони?
не копируя файлы из папок пира =)
п.с.
у тебя все поля обнулились(а также мой текст), когда я не ввёл майл. these is not friendly user interface =)
Май 26th, 2009 at 21:38
я думаю, что надо указать папку PEAR в include_path. а вообще я с пиром почти не общался.
p.s.> там написано, что вводить надо)) а форма стандартная для вордпресса
Июль 7th, 2009 at 05:58
Hello. I think the article is really interesting. I am even interested in reading more. How soon will you update your blog?
Август 11th, 2010 at 17:09
link_to_remote и ряд других хелперов убрали в sf 1.4 – приходится использовать чистый jQuery для формирования Post-запросов.
Август 11th, 2010 at 18:56
Да, спасибо. Можно еще поставить jq_reloaded плагин. Я думаю над тем, чтобы обновить плагин. На этот раз с jquery и doctrine. Поживем – увидим.