| « Поставить закладку » « Сделать стартовой » | |||
|
|||
|
Быстрое создание веб-приложений на Perl: вводная
Сейчас сложилась такая ситуация, что язык Perl незаслуженно забыт. Хочу немного поднять авторитет этого чудесного языка своими заметками.Эта макро-заметка ориентирована на изучающих Perl, знатоков этого языка, а так же на тех, которые только хотят побольше узнать о Perl. В заметке хочу поделиться просто своим опытом. Хочется рассмотреть простую ситуацию, которая по моему мнению, часто имеет место быть при разработке малых и средних проектов. А ситуация такая: необходимо создать небольшой (средний) сайт, причем принимается решение отказаться от CMS, так как движок нужен небольшой, наворотов в админке не нужно, сложность примерно 16-24 человеко/часов. Для примера требуется небольшой сайт, который будет содержать статьи определенного типа (обычные текстовые статьи) и новости. Плюс небольшая админка для добавления статей и новостей. Условимся, что у нас есть "большая" разница между этими двумя типами контента в рамках этой статьи. ПроблемаВ таких ситуациях довольно часто принимается решение написать свой велосипед, то есть движок. Рассмотрим именно такую ситуацию, на примере которой рассмотрим так же прелести Perl и CPAN. Полноценную реализацию MVC не предлагаю, это слишком много для нашего маленького проекта. Для Perl написан вагон и маленькая тележка фреймворков (как MVC, так и не очень), например отличный Catalyst, который очень и очень похож на RubyOnRails (или наоборот, я не в курсе хронологии). Так же есть множество поменьше, для любопытствующих стоит взглянуть сюда. Мы же для простоты реализуем похожий механизм, но попроще. Итак, посмотрим на составляющие нашего движка (LAMP — это as default) в виде модулей: 1. Данные — DBIx::Class 2. Отображение — Template Toolkit 3. Управление — своими руками Небольшое отступление. Я давно не люблю папку cgi-bin и всячески стараюсь ее избегать, почти на всех хостингах (а тем более дома) разрешены файлы .htaccess. Создаем такой файл в корневой папке проекта и записываем туда: Options +ExecCGIТеперь можно исполнять скрипты с расширением .pl прям в текущей директории. Кроме того страницей по умолчанию будет наш скрипт index.pl. Далее советую всегда создавать конфиг. Вариаций множество, каждому нравится по разному, у меня минимально это выглядит так: Ничего военного, сюда вносятся глобальные параметры проекта и экспортируются. ДанныеСтруктура БДВернемся к движку. Пункт первый — это работа с данными, за нее у нас будет отвечать пакет DBIx::Class, который включает несколько модулей. Для начала создадим простую БД, с которой мы будем работать. Не стоит критично относится к структуре базы, она максимально простая, так же синтаксис без всего лишнего, минимизируем затраты. Таблица пользователей содержит самые основные данные (учет посещений и прочих нас пока не волнует), таблица categories содержит разделы статей, например "автомото", "спорт", "кулинария" и т.п., таблица articles содержит собственно статьи, а таблица news - новости. В последней есть поле is_put_on_main, которое отвечает за показ новости на главной. Так же почти в каждой таблице я задаю кодировку — это привычка, кто уверен — не делайте. Отображение в кодХорошо, таблицы у нас есть, теперь необходимо отобразить их в коде. Модуль DBIx::Class позволяет полностью отойти от написания SQL-кода и общаться с таблицами, как с объектами. Работать с этим модулем можно двумя способами: либо вручную описывать структуры каждой таблицы, либо воспользоваться автоматикой. Рассмотрим оба способа по порядку. Ручной методСмотрим в код, далее будут пояснения. Создадим в корне нашего проекта папку с именем DB и в ней создадим четыре файла: User.pm, Category.pm, Article.pm, News.pm, вот содержимое этих файлов. Итак, небольшие пояснения. Имеем четыре очень похожих файла, сначала объявляем базовым модуль DBIx::Class, далее используя механизм __PACKAGE__ вызываем его методы, а именно: load_components - загружаем компоненты для нашего модуля (PK::Auto для работы с автоинкрементированными primary_key, Core — основной набор для работы со связями, строками и столбцами). Далее указываем таблицу, после чего добавляем названия столбцов. Для работы со столбцами таких типов, как datetime, date и timestamp используется небольшой модуль InflateColumn::DateTime. С помощью него поля указанных типов можно использовать в программе, как объекты типа DateTime, со всеми вытекающими удобствами. После чего указываем primary key (если он составной, то указываем несколько полей set_primary_key(qw/name1 name2/);. Далее находятся знакомые для знающих RubyOnRails методы has_many(), belongs_to() и другие. Эти методы предназначены для создания связей между таблицами. Документация по чудному модулю DBIx::Class, где все подробно описано, включая туториал и cookbook. Теперь нам нужно использовать сие чудо, для этого нам нужен модуль DBIx::Class::Shema, который является абстракцией схемы данных. В корневой папке проекта создаем файл с именем, идентичным имени папки с классами, описывающими таблицы, в нашем случае это будет DB.pm Вот как он выглядит у меня. В целом, использовать DBIx::Class::Schema можно и без функции GetShema(), метод load_classes() автоматически загружает все файлы, найденные в одноименной папке. Я дописал небольшую функцию, что бы удобнее было получать схему. Без этой функции соединение в коде выглядело бы так: В случае с функией можно написать их несколько либо по другому конфигурировать соединение с разными типа баз. Автоматический методВ "ручном" примере мы вручную задавали все связи между таблицами. Существует модуль DBIx::Class::Shema::Loader, который выполняет загрузку и создание классов автоматически. Для этого необходимо добавить в структуру БД описание внешних ключей (foreign keys). Используя их загрузчик автоматически создаст необходимые связи. Вот как это выглядит: Так же можно добавить выше функцию GetShema() (см. выше) и использовать ее. В данном случае папка DB и четыре файла в ней становятся не нужными и у нас остается один файл-описание схемы. Загрузчик поддерживает множество опций, которые задают пространство имен для создаваемых классов, параметры генерации имен классов, и другие. Использование схемыТеперь посмотрим, как это все вместе используется непосредственно в коде. Далее, покажем наши данные. ОтображениеЯ использую систему шаблонов Template Toolkit. Есть еще несколько систем, например Mason, но так исторически сложилось, что мой выбор пал на Template Toolkit. Template Toolkit — это система обработки шаблонов. Посмотрим ее использование сразу на примере. Для начала создадим в корне проекта папку tmpl и в ней создадим папку site. В папке tmpl/site создадим файл site следующего содержания: Далее, сделаем там же файл start_page: Вот такой простой файл с одной строчкой. Это будет заготовка нашей стартовой страницы. Свяжем все вместе и получим примерно такой код нашего скрипта index.pl: Две строчки про CGI думаю всем понятны, далее идет создание объекта Template, главным параметром которого является INCLUDE_PATH - пусть к шаблонам. Чуть ниже мы создаем схему данных и соединяемся с базой. Далее мы создаем хэш, в который будем складывать все переменные, которые необходимо передать в шаблон. В нашем случае мы передаем только одну переменную content, эта переменная используется в директиве PROCESS в шаблоне site. Еще ниже мы запускаем обработку шаблона и указываем стартовый шаблон - site, а так же передаем хэш переменных. В шаблоне site используется директива PROCESS, она запускает вложенную обработку другого шаблона, имя которого передано параметром, но так, как у нас имя хранится в переменной, то мы указываем это непосредственно - [% PROCESS $content %]. Таким образом в тело шаблона site вставится содержимое шаблона start_page. Добавим немного разнообразия. На главной странице мы должны отображать статьи и новости, но не все, а, скажем, последние десять. К тому же новости только те, которые помечены соответствующим флагом в таблице. Перед обработкой шаблона добавим в наш скрипт несколько строк: Следует заметить, что мы использовали [] для создания спискового контекста, иначе в скалярном контексте функция search() возвращает объект типа ResultSet, а нам нужен именно массив данных. Итак, подробно описывать не имеет смысла, так как все довольно явственно. Единственное, это использование параметров rows/page. Они необходимы для создания так называемых pager-ов, с помощью которых удобно организовывать постраничный вывод, а так же применяются для простого отбора записей, что является частным случаем. Так же кол-во статей и новостей можно вынести в конфиг. Далее, изменим шаблон start_page: Отмечу использование поля added_at, как объекта. Для него вызывается метод dmy(), который форматирует дату в формат ДД-ММ-ГГГГ с переданным разделителем, в нашем случае точка. Объект DateTime поддерживает локали и корректно отображает дату в зависимости от текущей (или выбранной) локали. Так же он содержит множество методов для форматирования и работы с датами. Я пока намеренно не добавлял валидные ссылки, сделаю это позже. В целом мы видим два похожих блока, которые стоит вынести в отельный файл. Создадим файл short_note в папке tmpl/site: Теперь наш шаблон start_page примет такой вид: Теперь мы вызываем обработку шаблона short_note и передаем ему в качестве параметра note текущую новость или статью. В шаблоне выполняется проверка на наличие поля category, что у нас будет признаком статьи, в этом случае мы выводим название раздела. На нашем портальчике так же необходимы шаблоны для отображения полной статьи или новости, отображение списка категорий статей, поисковая форма и результаты поиска. В целом, добавится еще несколько шаблонов, которые мало чем будут отличаться от вышеприведенных в плане сложности. УправлениеВыше мы условились не применять всяческих фреймворков, попробуем сделать минимум своими руками. Для этого сделаем следующую простую структуру (ламерскую, да-да): Итак, каждую ссылку в скрипте будет сопровождать параметр a - action. Он будет задавать текущий контекст. Таким образом, ссылки выше в шаблонах можно сменить на такие: Далее, нужно подумать о безопасности. Сейчас нас интересует только параметр id, на данный момент других у нас не используется. Сделаем самый простой финт ушами непосредственно перед разбором контекста: То есть, если у нас есть какой-то номер, будь то статьи, новости или каталога, то мы вырежем оттуда все не-цифры. Простой и дубовый метод. Рассмотрим далее примеры кода для контекстов. Поиск я не рассматривал, он довольно прост, из формы мы передаем введенные данные для поиска среди статей и новостей и выводим результаты. Так же стоит помнить, что в Perl существуют удобные модули для проверки данных на валидность, переданных из форм, например HTML-CheckArgs или HTML-QuickCheck. Существую более продвинутые инструменты, например HTML-Widget или HTML-Tag. Это полноценные системы для создания виджетов и проверки данных на валидность. Очень удобны в коде, а так же удобны для повторного использования. Единожды созданный виджет можно использовать во множестве приложений. В последнем случае есть небольшая дилемма: что делать, если задан неверный контекст. Некоторые склоняются к выводу ошибки (для этого нужно создать шаблон, например error_action, и просто указать на него), я же склонен отправлять всех на главную: Это не умно и не круто, зато безболезненно. Для тех, кто беспокоится о лишнем запросе к серверу, можно сделать следующим образом (до обработки контекста): То есть, если задан контекст и он присутствует в списке — использовать его, иначе установить 'start'. Хэш контекстов используется вместо массива для облегчения проверки - defined(...). АдминистрированиеДля администрирования необходимо создать некий инструмент. С точки зрения модели построения админка ничем не отличается от вышеприведенной системы, кроме авторизации и нюансов с текстом. Рекомендутеся создать отдельную папку для шаблонов, например tmpl/admin. Для авторизации я использую два инструмента: Digest::SHA1 и CGI::Session. Первый обеспечивает шифрование, второй — сессии. Итак, рассмотрим на простом примере применение этих инструментов. Пример намеренно упрощен до безобразия. Шаблоны: В скрипте админки нужно дописать вход и выход из системы, а так же сессии: Пример сильно дубовый, но тем не менее, он показывает суть. Модуль CGI::Session поддерживает хранение сессий как в файле, так и в БД. Так же необходимо указать срок истечения — expired. В примере использовано хранение в файлах в каталоге ssss. Модуль Digest::SHA1 - как альтернатива MD5. Следующий нюанс касается создания форм для ввода данных. Во-первых, необходимо создать так называемые CRUD-методы (CReate, Update, Delete). Для этого, например, существует модуль DBIx::Class::WebForm. Так же по запросу CRUD на CPAN можно найти еще несколько подобных модулей. Во-вторых, необходимо организовать удобный ввод текста статей и новостей. Лично я использую FCKeditor, хотя есть множество других. Такие редакторы довольно просто интегрируются в страничку и дают пользователям удобство и счастье в жизни. В-третьих, стоит позаботится о валидации данных из форм. Например, модуль DBIx::Class::Validation проверяет данные перед отсылкой в базу, так же есть всевозможные валидаторы данных из форм, которые работают совместно с виджетами или формами, например CGI::FormBuilder, CGI::QuickForm и т.д. По запросу "Form", "Validate" или "Widget" можно найти множество модулей для этих целей. ЗаключениеВ этой "небольшой" заметке я хотел поделиться своим небольшим опытом в создании простых приложений. Заметка вышла не маленькая, но, надеюсь, информативная. Приведенный здесь метод создания приложений очень эффективен в плане повторного использования, единожды созданные кусочки сайта можно потом использовать в других местах, почти ничего не меняя. Так же мы достаточно эффективно разделили вид и код, а так же абстрагировались от непосредственного написания SQL-запросов. Вот архив примера, а здесь - рабочий пример. На создание примера ушло меньше часа. -NOT_FOR_HOLYWARS- Автор: http://khizhaster.habrahabr.ru/ Рубрика: Perl
Вышел MySQL 5.1.30, первый стабильный рели....
После публикации 29 тестовых версий анонсирован первый стабильный релиз MySQL 5.1, пригодный для промышленной эксплуатации и обеспечивающий увеличение производительности для "тяжелых" SQL запросов, по сравнению с MySQL 5.0, примерно на 15-20%. Главные новшества появившиеся в MySQL 5.1:
Подробнее... |
Рубрика: MySQL
| Добавлено: 28.11.2008
Тестирование параллельных программ.
Тестирование параллельного программного обеспечения представляет собой более сложную задачу по сравнению с тестированием последовательной программы. Программист должен знать о подводных камнях при тестировании параллельного кода, имеющихся методологиях и инструментарии.
Подробнее... |
Рубрика: Тестирование
| Добавлено: 28.11.2008
Архитектура AMD64 (EM64T).
Аннотация. В статье кратко рассматривается архитектура AMD64 компании AMD и ее реализация EM64T компании Intel. Описаны особенности архитектуры, ее возможности, достоинства и недостатки.
Подробнее... |
Рубрика: Архитектура AMD
| Добавлено: 27.11.2008
Остальные статьи: |
Цитата дня (все,добавить):
|
Realcoding.NET
© 2003-2008 |
Контакты |
Реклама на сайте
|