:-)
  • PHP 24.04.2009

    Давно я не брал в руки шашек. То есть не писал про 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-классов. Ну а дальше, с помощью рефлексии мы вызываем метод для того, чтобы получить объект, над которым производим действия. Геттеры и сеттер имеют стандартные названия и их рефлексить нам не надо. После чего в ответ рендерим тот же самый компонент, который вернет нам картинку с аяксовой ссылкой на то же самое действие.

    Я догадываюсь, что это не так просто понять. Если будет совсем не в моготу - задавайте вопросы в комментариях.

    А еще я писал про:

    1. Symfony: динамический роутинг
    2. Symfony: категории и подкатегории
    3. Symfony: плагин sfPropelToggler 1.0.0b

    Tags: , , , , ,

  • 5 комментариев

    WP_Modern_Notepad
    • cainrus пишет:

      не подскажешь как использовать pear библиотеки в симфони?
      не копируя файлы из папок пира =)

      п.с.
      у тебя все поля обнулились(а также мой текст), когда я не ввёл майл. these is not friendly user interface =)

    • CharnaD пишет:

      я думаю, что надо указать папку PEAR в include_path. а вообще я с пиром почти не общался.

      p.s.> там написано, что вводить надо)) а форма стандартная для вордпресса

    • KonstantinMiller пишет:

      Hello. I think the article is really interesting. I am even interested in reading more. How soon will you update your blog?

    • qosys пишет:

      link_to_remote и ряд других хелперов убрали в sf 1.4 – приходится использовать чистый jQuery для формирования Post-запросов.

    • CharnaD пишет:

      Да, спасибо. Можно еще поставить jq_reloaded плагин. Я думаю над тем, чтобы обновить плагин. На этот раз с jquery и doctrine. Поживем – увидим.

    Trackbacks

    Оставить комментарий

    Внимание: Комментарии проходят премодерацию. Не надо посылать их несколько раз.