2008 Июль | Кирилл Павлюков
Июл 30

Вы, вероятно уже поняли, что мой любимый визуальный редактор (Rich Text Editor, по-буржуйски) – это SPAW Editor. Я уже неоднократно писал заметки о SPAW. В частности, о том, как подружить SPAW и WordPress, и как сделать плагин Spaw для Smarty. Сегодня пришло время подружить SPAW с не менее замечательной опенсорсной разработкой – Zend Framework.

Принципы интеграции

В общем-то, можно инстанционировать экземпляр SPAW просто в нужном контроллере действий, и передать его экземпляр скрипту вида, который выведет в нужном месте HTML-код. Но! Во-первых, это очень просто, а мы легких путей не ищем. А – главное – во-вторых, тогда потеряется возможность фильтрации и валидации введенных пользователями данных с помощью механизмов Zend_Form. Можно, конечно, самостоятельно произвести над данными необходимые действия. Но не кошерно это, что ли.

Итак, в этой статье я опишу, как сделать редактор SPAW полноценным элементом Zend_Form.

Для начала, разберем, что собой представляет HTML-вывод SPAW. Элементы ввода (для каждой страницы редактора) – это обычные textarea, которые обрамлены килобайтами трудночитаемого HTML и JS. Это довольно примитивная характеристика, но для понимания сути ее достаточно. Следовательно, нам необходимо всего лишь «завернуть» Zend_Form_Element_Textarea в соответствующую оболочку кода. Примерно так мы и поступим – мы напишем свой Zend_Form_Decorator.

Что необходимо

Так как SPAW может оперировать двумя типами объектов (объект редактора, собственно, и объект страницы), нам понадобится 2 соответствующих декоратора: My_Decorator_Spaw и My_Decorator_SpawPage.

При этом, My_Decorator_SpawPage – это вовсе не декоратор в философии Zend_Form, а лишь механизм, с помощью которого мы будем информировать My_Decorator_Spaw о наличие дополнительных страниц. Конечно это не правильно, но другого выхода я не придумал :-( . В свою очередь, такая реализация накладывает одно ограничение на использование: все дополнительные страницы редактора должны быть объявлены ДО объявления основной страницы.

Приступим

Для начала приведу код декоратора My_Decorator_SpawPage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

require_once $_SERVER['DOCUMENT_ROOT'] . '/spaw2/spaw.inc.php';

class My_Decorator_SpawPage extends Zend_Form_Decorator_Abstract
{
    public function render($content)
    {
        $element = $this->getElement();
        $element->setDisableLoadDefaultDecorators(true);
        $page = new SpawEditorPage($element->getName(),
                                   $element->getLabel(),
                                   $element->getValue(),
                                   $element->getAttrib('direction'));
        My_Decorator_Spaw::addPage($page);
        return NULL;
    }
}

Как видите, он создает объект страницы и передает его статическому методу My_Decorator_Spaw::addPage(). Этот метод сохраняет объект в хранилище My_Decorator_Spaw::$pages. Позже, при рендеринге основной части SPAW, все объекты страниц SpawEditorPage будут изъяты из этого хранилища. Конструктору SpawEditorPage передаюся 4 параметра, которые устанавливаются с помощью соответствующих методов объекта Zend_Form_Element_Textarea. Для понимания этого механизма либо обратитесь к мануалу, либо посмотрите раздел «Пример использования» в этой статье.

Ниже приведен код второго декоратора – My_Decorator_Spaw. Комментарии приведены в самом коде.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php

require_once $_SERVER['DOCUMENT_ROOT'] . '/spaw2/spaw.inc.php';

class My_Decorator_Spaw extends Zend_Form_Decorator_Abstract
{
    // объявим статическую переменную $pages - наше хранилище
    static $pages = array();

    // а это - статический метод для добавление объектов
    // страниц редактора в хранилище
    static function addPage($page) {
        array_push(self::$pages,$page);
    }
   
    // метод render() вызывается автоматически в момент генерации
    // кода элемента формы. Здесь и происходит перевоплощение обычной
    // textarea в полноценный визуальный редактор
    public function render($content)
    {
        // получим объект элемента формы для удобства доступа
        // к его свойствам
        $element = $this->getElement();
        // на всякий случай отключим дефолтные декораторы
        // для этого элемента
        $element->setDisableLoadDefaultDecorators(true);
        // создаем объект SpawEditor. В качестве параметров
        // передаются свойства элемента.
        $spaw = new SpawEditor($element->getName(),
                               $element->getValue(),
                               $element->getAttrib('language'),
                               $element->getAttrib('toolbarset'),
                               $element->getAttrib('theme'),
                               $element->getAttrib('width'),
                               $element->getAttrib('height'),
                               $element->getAttrib('stylesheet'),
                               $element->getLabel());
        // А это - небольшая хитрость. Дело в том, что конструктору
        // SpawEditor нельзя передать один параметр - направление письма.
        // Поэтому мы создадим страницу редактора с тем же именем.
        $page = new SpawEditorPage($element->getName(),
                                   $element->getLabel(),
                                   $element->getValue(),
                                   $element->getAttrib('direction'));
        $spaw->addPage($page);
       
        // Дальше следует проверка наличия дополнительных свойств,
        // и их установка для текущего объекта редактора
        if ($element->getAttrib('hideModeStrip')) {
            $spaw->hideModeStrip();
        }
        if ($element->getAttrib('hideStatusBar')) {
            $spaw->hideStatusBar();
        }
        if ($element->getAttrib('setFloatingMode')) {
            $spaw->setFloatingMode();
        }
        if (count($element->getAttrib('setStaticConfigValue')) > 0) {
            foreach ($element->getAttrib('setStaticConfigValue') as $name => $value) {
                SpawConfig::setStaticConfigValue($name,$value);
            }
        }
        if (count($element->getAttrib('setConfigValue')) > 0) {
            foreach ($element->getAttrib('setConfigValue') as $name => $value) {
                $spaw->setConfigValue($name,$value);
            }
        }        
       
        if (is_array($element->getAttrib('toolbar'))) {
            $toolbars = $element->getAttrib('toolbar');
            $element->getAttrib('toolbar');
            foreach ($toolbars as $toolbar) {
                    $spaw->addToolbar($toolbar);
                }
        }
       
        // Настало время извлечь из хранилища объекты дополнительных
        // страниц, и добавить объекту редактора
        foreach (self::$pages as $page) {
            $spaw->addPage($page);
        }
       
        // А дальше следует вывод. Комментарии, надеюсь, излишни.
        $separator = $this->getSeparator();
        $placement = $this->getPlacement();
        $output = $spaw->getHtml();

        switch ($placement) {
            case (self::PREPEND):
                return $output . $separator . $content;
            case (self::APPEND):
            default:
                return $content . $separator . $output;
        }
    }
}

Пример использования

Понять принцип использования вам поможет следующий код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// Создадим собственно объект формы.
$form = new Zend_Form();
// Теперь нужно создать элемент для дополнительной страницы редактора.
// В этом элементе будет содержаться перевод статьи на иврит.
// Создадим новый экземпляр Zend_Form_Element_Textarea,
// в качестве параметра конструктора передадим имя элемента
// формы - 'article_hebrew'
$page = new Zend_Form_Element_Textarea('article_hebrew');
// Установим для этой страницы Label
$page->setLabel('Hebrew translation');
// Следующие 2 строки применяют к элементу созданный нами
// декоратор My_Decorator_SpawPage
$page->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
$page->setDecorators(array('SpawPage'));
// При необходимости - указываем текущее значение элемента
// $page->setValue('Hebrew text');
// А теперь укажем направление текста - справа на лево.
$page->setOptions(array('direction' => 'rtl'));

// Теперь создадим основную страницу редактора с именем 'article'
$element = new Zend_Form_Element_Textarea('article');
// Установим Label
$element->setLabel('English article');
// Следующие 2 строки применяют к элементу декоратор My_Decorator_Spaw
$element->addPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
$element->setDecorators(array('Spaw'));
// При необходимости - указываем текущее значение элемента
// $element->setValue('111');
// Метод setOptions() устанавливает массив параметров для элемента.
// Эти параметры будут использованы для настройки объекта редактора.
// Больше информации об этих параметрах можно найти в документации по SPAW.
$element->setOptions(array('direction' => 'ltr',
                           'language' => 'ru',
                           'width' => '600px',
                           'height' => '400px',
                           'toolbar' => array('edit','font'),
                           'theme' => 'spaw2',
                           'stylesheet' => 'cust.css',
                           'hideModeStrip' => TRUE,
                           'setFloatingMode' => FALSE,
                           'hideStatusBar' => TRUE,
                           'setStaticConfigValue' => array('default_height' => '200px',
                                                           'default_width' => '200px'),
                           'setConfigValue' => array('default_height' => '500px',
                                                     'default_width' => '500px')));
// Вначале добавим в форму все дополнительные страницы редактора
$form->addElement($page);
// И лишь затем - основную страницу. Это связано с тем, что
// рендеринг элементов происходит в порядке их добавления.
$form->addElement($element);
// Теперь можно вывести форму или передать ее в скрипт вида либо на обработку.
echo $form->render();

Послесловие

Вероятно, я выбрал не очень «изящный» способ интеграции. Но он наиболее легко реализуем. Если у вас будут другие соображения, как подружить SPAW и Zend Framework, пишите каменты – обсудим!

Share

Автор: Кирилл Павлюков \\ Метки: , , , ,

Июл 28

Nested Sets переводится на русский как Вложенные множества. Это один из способов хранения древовидных структур в базе данных. В свое время этот механизм обсуждался очень бурно, поэтому нагуглить информацию по теме не составит труда. Но если гуглить по понедельникам вам не позволяет вероисповедание, можно просто ограничиться статьей, опубликованной еще в далеком 2003 на phpclub.ru. Для понимания принципов и алгоритмов вполне достаточно.

ИМХО, Nested Sets – это идеальный способ хранения деревьев, если требуется делать много выборок, а редактирование дерева происходит намного реже.

Но я немного увлекся – тема постинга немного другая.

Чтобы пользоваться всеми прелестями Nested Sets под Zend Framework, нужно было адаптировать один из имеющихся в сети классов для работы с таким типом деревьев под фреймворк. Признаться, я давно хотел это сделать. Но так как в работе такой потребности пока не возникало, а по природе своей я очень ленив, то все мои потуги заканчивались лишь несколькими десятками строк.

А тут сегодня на блоге http://web-dev.info/ обнаружил, что такой класс уже написан. Радости моей не было предела. А автору – респект и уважуха :-)

Share

Автор: Кирилл Павлюков \\ Метки: , ,

Июл 28

НЕБОЛЬШОЙ ОФТОП. В последнее время в моей оффлайновой жизни произошли некоторые изменения. Связаны они с людьми, которые долгое время окружали меня, но на поверку оказались редкостным дерьмом. Так вот, из-за этих изменений я неделю занимался ничегониделаньем, поэтому пропустил жизненноважное событие – выход Zend Framework 1.6 RC1.

Теперь по теме.

Собственно, все уже отписали, что могли. Так что, мне придется ограничиться несколькими ссылками на то, что было сказано до меня.

Олег Лобач в своем блоге, в общем-то, просто пересказывает заметку с офсайта о нововведениях на русском. Кстати, пересказ получился довольно-таки вольным и кратким. Так что, что для пущей информированности читайте Zend Developer Zone.

А на здесь объясняется, почему фреймворк так «набрал в весе». Оказывается, всему виной Dojo, которым вообще можно и не засорять свой сервер – в случае отсутствия последнего, он будет подгружаться с сайтов Google, AOL и др.

Короче, поздравляю вас с еще одним шагом в развитии Zend Framework. Заодно предостережение от разработчиков – RC1 – это всего лишь релиз кандидат, а не полноценный релиз. Поэтому использовать его в продакшене не рекомендуется.

ЗЫ. А мне пофиг. Я сейчас начинаю переписывать один из своих старых проектов. И в качестве технологической платформы возьму ZF. Там хоть и полный продакшн, но сервер у меня постоянно под присмотром… Надеюсь и молюсь за отсутствие глюков )

ЗЗЫ. Если вы не знаете, что такое Zend Framework, рекомендую почитать здесь – http://ru.wikipedia.org/wiki/Zend_Framework. А если коротко, то это полноценный фреймворк для быстрой разработки сайтов на PHP.

Share

Автор: Кирилл Павлюков \\ Метки: ,

Июл 16

Сегодня почему-то вспомнился наш апрельский отдых в Кемере… Нашел в сети несколько турецких песен – порадовался. Кто хоть раз был в Турции обязан иметь такой сборник на своем компе. Must have, одним словом

В общем, делюсь с общественностью. Качайте на здоровье, притом бесплатно:

  • 01 Дорожка 1.wma 
  • 02 Дорожка 2.wma
  • 03 Дорожка 3.wma
  • 04 Дорожка 4.wma 
  • 05 Дорожка 5.wma 
  • 06 Дорожка 6.wma 
  • 07 Дорожка 7.wma 
  • 08 Дорожка 8.wma
  • 09 Дорожка 9.wma
  • 10 Дорожка 10.wma 
  • 11 Дорожка 11.wma 
  • 12 Дорожка 12.wma
  • 13 Дорожка 13.wma 
  • 14 Дорожка 14.wma 
  • 15 Дорожка 15.wma 
  • 16 Дорожка 16.wma
  • 17 Дорожка 17.wma 
Share

Автор: Кирилл Павлюков \\ Метки:

Июл 16

На днях просматривал статистику поисковых запросов, по которым пользователи находят этот блог. Оказалось, что много запросов связаны с установкой ICQ. Не знаю, может, это админы удаляют аськи с компьютеров коллег. Или, как вариант, пользователи просто не умеют сами установить программу. Но факт остается – тема требует своего раскрытия. Итак, начнем.

Как установить аську (ICQ, QIP)?
Пошаговое руководство

1) Для начала нужно определиться, с каким ICQ-клиентом вам хотелось бы работать. Из наиболее распространенных могу предложить на выбор собственно ICQ6 или QIP. Я уже давно выбрал для себя второй вариант, так как он быстрее работает, меньше тормозит, в нем не было замечено глюков с кодировкой текста, и – главное – в нем отсутствует назойливая реклама.

2) Скачать ICQ (аську, квип, клиента… кто как хочет, тот так и называет). Так вот, скачать можно либо с официальных сайтов (QIP – http://qip.ru/, ICQ – http://icq.com/), либо воспользовавшись приведенными ниже ссылками.

Скачать QIP версии 8070 (самая свежая версия на сегодняшний день)

 Вариант Ссылка  Примечание 
 EXE (2Мб)  http://fileshare.in.ua/879426 Этот вариант требует соответствующих прав для установки на компьютер. Если у вас нет достаточных прав, воспользуйтесь одной из двух ссылок, приведенных ниже.
 ZIP (1,9Мб)   http://fileshare.in.ua/879440
 RAR (1,9Мб)  http://fileshare.in.ua/879443

Скачать ICQ версии 6 (самая свежая версия на сегодняшний день)


 Вариант Ссылка  Примечание 
русский язык (13,9Мб) http://fileshare.in.ua/879455 Оба варианта требуют установки. Поэтому могут не подойти, если админ не дал вам соответствующих прав на установку программ. 
украинский язык(13,6Мб) http://fileshare.in.ua/879459

3) Установить ICQ (аську). В зависимости от того, какой вариант клиента вы выбрали, дальнейшие действия будут немного различаться.

После загрузки дважды кликните на имени загруженного файла в проводнике, и следуйте инструкциям мастера установки. Каждое действие, которое необходимо выполнить, будет показано на экране.

В будущем вы сможете запускать аську из меню «Пуск», или кликнув на нужном ярлыке на Рабочем столе.

Share

Автор: Кирилл Павлюков \\ Метки: