пример | Кирилл Павлюков
Сен 09

Недавно на нашем основном сайте упала посещаемость. При этом поток с поисковых систем был на прежнем уровне, а количество посетителей с новостных информеров пошло вниз. Сверив статистику, мы были удивлены, что одному из партнеров мы отдавали в день около 300-500 посетителей, что, в принципе, очень мало.
Учитывая то, что недавно этот партнер (якобы случайно) нарушил достигнутые между нами договоренности, нам присланная статистика показалась заниженной. Я начал думать, как можно посчитать количество переходов, если информер – это яваскрипт, который отрабатывается на стороне клиента.

И в этом на помощь пришел jQuery!
Несколько строк кода – и переходы по внешним ссылкам считаются нашим сервером!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// подключаем jQuery
<script src="http://code.jquery.com/jquery-latest.js"></script>
// подключаем класс для работы с base64
<script src="http://www.zavtra.com.ua/jscripts/base64.js"></script>
 
<script>
// при загрузке документа...
$(document).ready(function(){
// получить массив все ссылки, которые содержат текст "xxx.yyy" в аттрибуте href
var x= $("a[href*='xxx.yyy']");
// для каждой найденной ссылки...
jQuery.each(x, function() {
  // url - это старый адрес закодированный по Base64
  url = Base64.encode($(this).attr("href"));
  // назначаем новый аттрибут href: адрес PHP-скрипта на нашем сервере,
  // и в качестве строки запроса - полученный в прошлой строке урл
  $(this).attr("href", "http://www.zavtra.com.ua/go2un.php?" + url);
});

});
</script>

Вуаля! Теперь все переходы идут через скрипт на нашем сервере. А в этом скрипте мы записываем информацию о переходе в лог-файл и перенаправляем пользователя по адресу, который получаем из раскодированной строки запроса.

Share

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

Ноя 13

Признаться, сложного в этом нет ничего. Но, к примеру, редактор нашего сайта этого не умеет. Поэтому изначально заметку на эту тему изначально я планировал написать именно для него. Но потом проверил статистику Яндекса, я пришел к выводу, что 368 человек в месяц пытаются найти что-то по запросу «вставить ссылку». Пусть это и не большая аудитория, но мне будет приятно, если хоть кому-нибудь эта заметка пригодится.

Итак, для начала давайте разберемся, каким образом можно вообще вставить ссылку на странице.

Во-первых, если вы используете визуальный редактор, то в нем наверняка должна быть соответствующая задаче кнопка. Чаще все она выглядит как пиктограмма из 3 горизонтально размещенных звеньев цепи. Выделите фрагмент текста, который хотите сделать гиперссылкой, нажмите на кнопку, и в появившемся окошке введите адрес, на который должен перейти пользователь, кликнувший по ссылке. Чаще всего там же можно указать и другие параметры.

КСТАТИ
Не забывайте, что имена файлов, выкладываемых в Интернет чаще всего чувствительны к регистру. Поэтому для сервера Foto.JPG и foto.jpg – абсолютно разные файлы. К тому же по правилам языка HTML (если говорить весьма упрощенно) все русские символы адреса и пробелы должны заменяться соответствующими им кодами (например пробел должен быть заменен на %20). Чтобы упростить себе жизнь и не портить нервы, лучше используйте в названиях файлов только английские буквы, цифры, дефис и нижнее подчеркивание.
И еще. Не забывайте о том, что если ссылка ссылается на файл, то его имя обязательно должно заканчиваться расширением (например, .mp3 или .jpg)

Второй вариант – это вставлять ссылку непосредственно в HTML-код страницы. Для этой цели служит HTML-тег <a>. В самом простом варианте ссылка должны выглядеть так:

<a href=»адрес_ссылки»>текст ссылки</a>

, где адрес_ссылки - это адрес, по которому пользователь будет перенаправлен, кликнув по ссылке, а текст ссылки - это, собственно, текст, который отобразится на странице.

КСТАТИ
Адреса ссылок могут быть абсолютными или относительными. Абсолютный (или полный) адрес выглядит так: http://www-reestr-zalogov.ru/files/testImage.jpg. То есть, он включает в себя кроме имени файла еще и протокол (в приведенном примере – http) и имя сервера.
Но если ссылаться на страничку или файл, находящийся на этом же сервере, то можно использовать относительные адреса. Тогда приведенный выше адрес ссылки можно было бы сократить до такого: /files/testImage.jpg. Ну, а если бы страница, в которую вы вставляете ссылку, находилась бы в той же папке (в примере – files/), тогда в роли адреса выступало бы только имя файла – testImage.jpg

И третий вариант – использование так называемых BB-кодов. Использование BB-кодов не сильно отличается от HTML, поэтому я просто ограничусь примерами:

[url]адрес_ссылки[/url]
[url=адрес_ссылки]текст ссылки[/url]

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

Вставляйте ссылки грамотно!
Успехов!

Share

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

Окт 12

Недавно Владимир в комментариях к заметке о SPAW задал вопрос относительно вставки уменьшенных копий изображения.

В свое время передо мной тоже стояла такая задача. Здесь я расскажу о том, как я решил ее в своем проекте.

Для начала теория. Вставив ибображение на странице редактора SPAW, вы можете задать ему практически любой доступный HTML-атрибут, а также изменить размер изображения до необходимого вам минимума. Затем, на стороне сервера с помощью регулярных выражений можно извлечь из текста все изображения и обработать их, и привести к нужному виду.

В последнем проекте (новостной сайт) была необходимость создания превьюшек, а также максимально легко добавлять к изображениям подпись и источник, откуда оно было взято. Подпись редакторы указывали в атрибуте alt, источник – в title, а необходимые размеры брались из style. Кроме того, использовался и атрибут align.

Ниже приведен код метода из контроллера действий News (проект написан на Zend Framework), который отвечал за необходимый мне функционал. Код снабжен большим количеством комментариев, поэтому отдельно я его описывать не стану. Если возникнут вопросы – задавайте их в комментариях.

Читать запись полностью »

Share

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

Сен 04

Это перевод второй части статьи с DevZone об использовании Zend_Acl MVC Zend Framework.

В первой части мы говорили о том, как настроить экземпляр Zend_Acl, и как присоединить его к окружению MVC (с использованием плагина фронт-контроллера). Но как насчет установки другого действия для обработки запрета доступа, или как сделать, чтобы статью мог редактировать только ее владелец? Это и кое-то другое вы найдете в приведенных ниже примерах.

Как я упоминал в первой части, эта статья основана на Предложениях Zend Framework (ссылка), которая в настоящее время находится в лаборатории (Лаборатория – часть кода и концепции Zend Framework, которая внесена в проект, но дожидается утверждения для внесения в основной релиз, – прим. переводчика).

1. Использование модулей

Давайте поговорим об использовании модулей. Мы использовали в качестве примера для данной статьи сайт аналогичный devzone. Как насчет того, чтобы создать административный модуль, для утверждения (одобрения) статей и некоторых других задач (например, измениения быстрых ссылок или разделов)? Для этого нам потребуется изменить модель ресурсов нашего ACL:

Модуль по-умолчанию:

  • Контроллер user.
  • Контроллер article.

Административный модуль:

  • Контроллер article.
  • Контроллер quick-link.
  • Контроллер category.

Основываясь на данной модели ресурсов, создадим экземпляр Zend_Acl, отображающий это.

ВАЖНО
Помните, этот код и создание объекта Zend_Acl должны быть выполнены до вызова метода диспетчеризации фронт-контроллера (в файле bootstrap).

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
/** Создание Ролей */
require_once 'Zend/Acl/Role.php';
$myAcl->addRole(new Zend_Acl_Role('guest'))
      ->addRole(new Zend_Acl_Role('writer'), 'guest')
      ->addRole(new Zend_Acl_Role('admin'), 'writer');

/** Создание Ресурсов */
require_once 'Zend/Acl/Resource.php';
/** Модуль по-умолчанию */
$myAcl->add(new Zend_Acl_Resource('user'))
      ->add(new Zend_Acl_Resource('article'));

/** Административный модуль */
$myAcl->add(new Zend_Acl_Resource('admin'))
      ->add(new Zend_Acl_Resource('admin:article', 'admin'))
      ->add(new Zend_Acl_Resource('admin:quick-link', 'admin'))
      ->add(new Zend_Acl_Resource('admin:category', 'admin'));

/** Создание привелегий */
$myAcl->allow('guest', 'user')
      ->deny('guest', 'article')
      ->allow('guest', 'article', 'view')
      ->allow(array('writer', 'admin'), 'article', array('add', 'edit'))
      ->allow('admin', 'admin');

/** Установка фронт-контроллера */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory(array('default' => 'path/to/default/controllers',
                                     'admin' => 'path/to/admin/controllers'));

/** Регистрация объекта плагина */
require_once 'Zend/Controller/Plugin/Acl.php';
$front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, 'guest'));

/** Запуск диспетчеризации */
$front->dispatch();

Заметьте, мы создали ресурс для каждого контроллера модуля по-умолчанию, а для административного модуля – ресурс для самого модуля и по одному для каждого контроллера внутри модуля (в формате ‘модуль:контроллер’), которые являются дочерними по отношению к ресурсу модуля администрирования. Кроме того мы указали, что только пользователи с административной ролью имеют доступ к административному модулю.

2. Использование ролей

Войдя в приложение, пользователь должен получить одну из ролей (в нашем примере роль может быть ‘guest, ‘writer’ или ‘admin’). Так как же мы можем определить роль в наших приложениях? Для начала необходимо сохранить роль в переменной, которая хранится в сессии. Поэтому, после авторизации пользователя, нужно сохранить его роль в хранилище сессии, а при последующих запросах, извлечь ее из сессии, чтобы передать плагину фронт-контроллера в bootstrap-файле.

Контроллер User

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
user controller class UserController extends Zend_Controller_Action
{
    protected $_application;

    public function init()
    {
        require_once 'Zend/Session/Namespace.php';
        $this->_application = new Zend_Session_Namespace('myApplication');
    }

    public function loginAction()
    {
        ... Код проверки авторизации
        if ($valid) {
            /** Сохранение роли в сессии */
            $this->_application->currentRole = $user->role;
            $this->_application->loggedUser = $user->username;
        }
    }

    public function logoutAction()
    {
        $this->_application->currentRole = 'guest';
        $this->_application->loggedUser = null;
    }
}

bootstrap-файл

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/** Загрузка данных приложения из сессии */
require_once 'Zend/Session/Namespace.php';
$application = new Zend_Session_Namespace('myApplication');

if (!isset($application->currentRole)) {
    $application->currentRole = 'guest';
}

/** Установка фронт-контроллера */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('path/to/controllers');

/** Регистрация объекта плагина */
require_once 'Zend/Controller/Plugin/Acl.php';
$front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application->currentRole));

/** Запуск диспетчеризации */
$front->dispatch();

3. Установка действия, отображаемого в случае запрета доступа

Возможно, некоторым из вас (надеюсь, никому =D) просто не понравится идея хранения действия, отображаемого в случае запрета доступа, в контроллере ошибок (error controller), или просто захочется иметь какой-то обходной путь. В этом случае вам поможет метод setErrorPage плагина фронт-контроллера.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/** Установка фронт-контроллера */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('path/to/controllers');
 
/** Установка действия, отображаемого в случае запрета доступа  */
require_once 'Zend/Controller/Plugin/Acl.php';
$aclPlugin = new Zend_Controller_Plugin_Acl($myAcl, 'guest');
$aclPlugin->setErrorPage('goaway', 'my-error-controller', 'my-module');

/** Регистрация объекта плагина */
$front->registerPlugin($aclPlugin);
 
/** Запуск диспетчеризации */
$front->dispatch();

К методу setErrorPage можно обратиться, указав только имя действия (в этом случае будут использованы имя контроллера и модуля по-умолчанию: ‘error’ и ‘default’ соответственно), но также можно передать методу действие и контроллер или все три параметра.

4. Использование помощника действий

В конце мы рассмотрим одну из наиболее важных частей этого предложения: как на примере devzone только авторам и администраторам разрешить редактировать статьи (Но, стоп: здесь есть упущенный момент. Если я – автор, и у меня есть доступ к article/edit/:id, в таком случае я смогу редактировать не только свои статьи, но и чужие. Это проблема, не так ли? Итак, что же нам теперь делать? Управлять с помощью помощника действий (Action Helper), который позволит обратиться к нашему ACL внутри любого контроллера, а не только во время запуска.
Итак, перво-наперво нам нужно зарегистрировать наш плагин фронт-контроллера и Controller Action Helper Broker.
Bootstrap-файл

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/** Загрузка данных приложения из сессии */
require_once 'Zend/Session/Namespace.php';
$application = new Zend_Session_Namespace('myApplication');

if (!isset($application->loggedUser)) {
    $application->loggedUser = null;
}

/** Установка фронт-контроллера */
require_once 'Zend/Controller/Front.php';
$front = Zend_Controller_Front::getInstance();
$front->setControllerDirectory('path/to/controllers');

/** Регистрация объекта плагина */
require_once 'Zend/Controller/Plugin/Acl.php';
$front->registerPlugin(new Zend_Controller_Plugin_Acl($myAcl, $application->currentRole));

/** Регистрация объекта Action Helper */
require_once 'Zend/Controller/Action/Helper/Acl.php';
require_once 'Zend/Controller/Action/HelperBroker.php';
Zend_Controller_Action_HelperBroker::addHelper(new Zend_Controller_Action_Helper_Acl());

/** Запуск диспетчеризации */
$front->dispatch();

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

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
article controller class ArticleController extends Zend_Controller_Action
{
    protected $_acl;
    protected $_application;
 
    public function init()
    {
        /** Получаем наш помощник действия (Action Helper) */
        $this->_acl = $this->_helper->getHelper('acl');

        require_once 'Zend/Session/Namespace.php';
        $this->_application = new Zend_Session_Namespace('myApplication');
    }

    ...
 
    public function editAction()
    {
        /** Получаем статью по id */
        $article = new Article($this->_request->id);

        /** Проверяем, является ли пользователь владельцем или администратором */
        if (($article->author != $this->_application->loggedUser) && ($this->_application->currentRole != 'admin')) {
            $this->_acl->denyAccess();
        }
 
        ...
    }
}

Заключение

И последняя рекомендация: придерживайтесь принципа Оставлять Все Простым (Keep It Simple). Если вам не нужны динамически подгружаемые ACL, написанные руками правила – это не грех, это только лишь лучший способ реализовать необходимый функционал.

Автор статьи: Альдемар Берналь

Автор перевода: Кирилл Павлюков

Дополнительная информация:
Zend_Acl & MVC IntegrationА здесь вы найдете исходный код примеров к данной статье:
Исходный код
Оригинал статьи на DevZone:
http://devzone.zend.com/article/3510-Zend_Acl-and-MVC-Integration-Part-II-Advanced-Use

Share

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

Авг 29

На сайте разработчиков Zend Framework еще в конце июня появилась статья об интеграции Zend_Acl и парадигмы MVC. Несмотря на полезность и актуальность информации, до сих пор я не встречал перевода этой статьи на русский язык. Ниже приведена моя попытка исправить это. Кроме того, я уже заканчиваю перевод продолжения этого материала, поэтому к понедельнику выложу и его.

Так что же не правильного в компоненте Zend_Acl и текущей реализации MVC в Zend Framework? Нет ничего неправильного, просто для разработчиков не вполне очевидно, как достичь оптимальной интеграции этих двух важнейших частей фреймворка.

Стоит отметить, что данная статья основана на текущих Предложениях к Zend Framework (ссылка), но в данный момент эти рекомендации находятся на утверждении. Окей! Как это работает? Для реализации этого в Предложениях существует два ключевых компонента:

  1. Плагин фронт-контроллера (Front Controller Plugin). Этот компонент проверяет, имеет ли текущий пользователь доступ к запрашиваемой странице.
  2. Помощник действий (Action Helper). Этот компонент позволяет делать проверку прав доступа пользователя внутри контроллера действий.

Давайте возьмем за основу эти два компонента, и попробуем воспользоваться ими на примере. В дальнейшем мы будем вести разговор о сайте на подобии DevZone. Нам будут необходимы один контроллер, который управляет администрированием пользователей, и второй – для управления статьями. Также нам нужны 3 типа пользователей (ролей): один для гостей, второй – для авторов, и еще один, с помощью которого мы будем утверждать статьи. Вот все что нам нужно:

Ресурсы:

  • Контроллер user.
  • Контроллер article.

Роли:

Share

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

Июл 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

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

Июн 04

Давно не писал в блог. Каюсь. Весь погрузился в бумажную работу и изучение новых для меня областей знаний.

Ну, да ладно. Возвращаюсь к теме. Душа потребовала заменить установленный на блоге редактор TinyMCE на что-нибудь более удобное. Выбор был сделан в пользу SPAW Editor. (К слову, я уже делал несколько постов по этой теме. Найти их можно здесь и здесь.)

Установка безумно проста и не требует никаких глубоких знаний.

Читать запись полностью »

Share

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

Апр 18

Анализируя статистику поисковых запросов, по которым вы находите мой блог, я заметил, что много людей ищут примеры работы с Zend_Form. Для меня это показалось несколько странным, так как компонент Zend_Form хорошо документирован в руководстве. Но чего не сделаешь по просьбам читателей :-)

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

Для начала разберемся, что позволяет делать Zend_Form:

  • генерировать формы;
  • валидировать их (проверять введенные пользователем данные);
  • выводить ошибки.

Логично, что одна и та же форма может быть востребована несколько раз. Из этого следует, что код генерации формы можно вынести в отдельный метод для многократного использования. Так мы и поступим, создав действия getRegistrationForm и getLoginForm.

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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
private function getLoginForm()
{
    $translate = include(APP_DIR . DIRECTORY_SEPARATOR . 'translation.php');
    $translator = new Zend_Translate_Adapter_Array($translate);

    $form = new Zend_Form();
    $form->setAction('/auth/login')
         ->setMethod('post')
         ->setTranslator($translator);
    $form->addElements(array(
        new Zend_Form_Element_Text('email', array(
            'required' => true,
            'label' => 'Адрес e-mail:',
            'description' => 'Е-меил используется в качестве логина для входа на сайт',
            'validators' => array(
                array('NotEmpty', true),
                'EmailAddress'
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                array('Description'),
                )
            )),
        new Zend_Form_Element_Password('password',array(
            'required' => true,
            'label' => 'Пароль:',
            'description' => 'Выберите себе пароль',
            'validators' => array(
                array('NotEmpty', true),
                array('StringLength', true, array('min' => 6)),
                'Alnum'
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                )
            )),
        new Zend_Form_Element_Submit('Войти',array(
            'decorators' => array(
                array('ViewHelper'),
                array('HtmlTag', array('tag' => 'center')),
                )
            ))
        ));
       
    return $form;
}
   
private function getRegistrationForm()
{
    $translate = include(APP_DIR . DIRECTORY_SEPARATOR . 'translation.php');
    $translator = new Zend_Translate_Adapter_Array($translate);
    $form = new Zend_Form();
    $form->setAction('/auth/registration')
         ->setMethod('post')
         ->setTranslator($translator);
    $form->addElements(array(
        new Zend_Form_Element_Text('email', array(
        'required' => true,
            'label' => 'Адрес e-mail:',
            'description' => 'Е-меил используется в качестве логина для входа на сайт',
            'validators' => array(
                array('NotEmpty', true),
                array(new My_Validate_Unique('users','email'), true),
                'EmailAddress'
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                array('Description'),
                )
            )),
        new Zend_Form_Element_Password('password',array(
            'required' => true,
            'label' => 'Пароль:',
            'description' => 'Выберите себе пароль',
            'validators' => array(
                array('NotEmpty', true),
                array('StringLength', true, array('min' => 6)),
                'Alnum'
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                )
            )),
        new Zend_Form_Element_Password('password_confirm',array(
            'required' => true,
            'label' => 'Повтор пароля',
            'description' => 'Повторите ввод пароля',
            'validators' => array(
                array(new My_Validate_Password(), true)
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                )
            )),
        new Zend_Form_Element_Text('name', array(
            'required' => false,
            'label' => 'Ваше имя',
            'validators' => array(
                'Alnum'
                ),
            'decorators' => array(
                array('ViewHelper'),
                array('Errors'),
                array('HtmlTag', array('tag' => 'dd')),
                array('Label', array('tag' => 'dt','requiredSuffix' => ' (*)')),
                )
            )),
        new Zend_Form_Element_Submit('Зарегистрировать',array(
            'decorators' => array(
                array('ViewHelper'),
                array('HtmlTag', array('tag' => 'center')),
                )
            ))
        ));
    return $form;
}

Я оставлю пока этот листинг без комментариев, так как если описывать все в одном посте, то получится целый толмуд. Детально я буду рассматривать процесс создания форм в следующих постах (ориентировочно – на следующей неделе). Пока просто поверьте мне на слово, что этот код работает! (Внизу страницы вы сможете найти ссылку на архив, в котором есть файл контроллера и самописные валидаторы, используемые для проверки приведенных форм).

Итак, формы созданы, теперь нужно их использовать :-)
Посмотрите, как выглядит действие registration:

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
public function registrationAction()
{
    // проверим, переданы скрипту данные по методу POST
    if (!$this->getRequest()->isPost()) {
        // если данные не переданы, просто передадим в скрипт вида форму
        return $this->view->form = $this->getRegistrationForm();
    } else {
        $form = $this->getRegistrationForm();
        // если данные переданы, проверим их на корректность
        if (!$form->isValid($_POST)) {
            // если данные не корректны, возвращаем форму в скрипт вида
            // Zend_Form сам отобразит сообщения об ошибках
            return $this->view->form = $form;
        } else {
            // если данные верны, сохраним их в БД
            /** @var Zend_Db_Adapter_Abstract */        
            $db = Zend_Registry::get('db');
       
            if ($db->insert('users', array(
                'name' => $_POST['name'],
                'email' => $_POST['email'],
                'passwd' => new Zend_Db_Expr("MD5('{$_POST['password']}')"),
                ))) {
                $this->view->success = true;
            }
        }
    }
}

В скрипте вида можно формы можно использовать двумя способами. Во-первых, можно вывести форму целиком (что должно вас устроить в 99% случаев). Для этого нужно лишь добавить в скрипт вида инструкцию

1
<?php echo $this->form; ?>

Во-вторых, можно вывести поэлементно. Для этого в нужном месте вызывается код

1
<?php echo $this->form->element; ?>

, в котором element – это имя соответствующего элемента формы.

Share

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