12 января 2012 г.

Битрикс головоломка


В предыдущем посте посвященном ЧПУ Битрикс, был задан вопрос такого содержания:
Скажем есть инфоблок КАТАЛОГ, в нем раздел ТЕЛЕФОНЫ, в нем подраздел НОКИЯ, вот как в обработке адресов правильно написать условие, если мы не используем стандартные битриксовые убогие айди-чпу для комплексного компонента?

Единственное, что мне пока пришло в голову - это использовать уникальный символьный код каждого отдельного товара.

Надеюсь Вы поймете мой ход мыслей и если что подправите.
Допустим у нас такая иерархия:
КАТАЛОГ (тип инфоблока: katalog)
\_раздел ТЕЛЕФОНЫ ( инфоблок: phone)
| \_ подраздел НОКИЯ (символьный код раздела: nokia_phone)
| | \_ телефон1 (символьный код элемента: code1)
| | |_ телефон2 (code2)
| |- подраздел САМСУНГ (символьный код раздела: samsyng_phone)
| | \_ телефон3 (code3)
| | |_ телефон4 (code4)
| |...

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

Каждый элемент инфоблока для использования его #CODE# в ЧПУ должен содержать уникальный символьный код. Как настроить всю вязанку компонентов Битрикс  для учета и символьного кода раздела я еще не представляю.. 

Каталог Мобильных телефонов.
В параметрах компонентах, в поле URL страницы детального просмотра можно указать ЧПУ адрес вида:
/mobile/#SECTION_CODE#/#CODE#/
где #SECTION_CODE# - поле подстановки "символьный код раздела"
#CODE# поле подстановки "символьный код элемента"

В обработку адресов можно добавить следующую запись.
Условие:
#^/mobile/([\w\d\_]+)/([\w\d\_]+)/#
Файл: 
указать url адрес на страницу с компонентом детального просмотра
Правило:
SECTION_CODE=$1&CODE=$2

Итого:
Имеется url адрес /mobile/nokia_phone/code2/, где смысловую нагрузку несет только code2

10 января 2012 г.

Клонирование объектов Java-script


Парадоксальная ситуация Javascript объектно ориентированный язык программирование, но в нем нет встроенных механизмов для клонирования объектов. Чехарда с передачей ссылок на объекты "деревенским" присваиванием всеже не всегда нужна.
Когда мне понадобился рабочий код для копирования объектов, то я довольно быстро нашел по блогам готовые решения.
Но в дальнейшем, под действием ряда факторов его пришлось модифицировать.
Поэтому представляю свой метод-функцию копирования объектов java-script:

// notUseRecursion - опция копирования свойств объекта без использования рекурсии (сохраняются ссылки).
// Полное копирование объекта события в IE это его смерть от выхода за пределы памяти.
// Поэтому есть смысл его отключить
function clone(o,notUseRecursion) {// Out of the memory in IE8
    if(!o || 'object' !== typeof o)  return o;
    var     c = 'function' === typeof o.pop ? [] : {},
            p, v;
    for(p in o) {
        //if(o.hasOwnProperty(p)) {// Dont supported in IE8
        if (Object.prototype.hasOwnProperty.call(o,p)){
            v = o[p];
            c[p] = (v && 'object' === typeof v && !notUseRecursion)?clone(v):v;
        }
    } 
    return c;
}

Основные особенности, которые пришлось учесть в коде функции клонирования - это перлы Internet Explorer 6-8:
1) Свойство объекта hasOwnProperty() не поддерживается, в место него происходит применение одноименной функции прототипа объекта Object (см. код).
2) Рекурсивное копирование объекта события (window.event к примеру) - приводило к остановке выполнения скрипта от "out of the memory". Объект события содержит методы "нативного кода" (Native code) который лучше не копировать, а сохранять ссылки на них. Поэтому есть смысл скопировать объект без использования рекурсии (notUseRecursion=yes).
Если найду еще какие-нибудь препятствия на пути свободного копирования объектов, обязательно опубликую их в блоге...

9 января 2012 г.

Snap - Haskell web framework

Snap прежде всего первый веб фреймворк на Haskell с которым я познакомился и в общем, этот пост основан на том опыте который я получил тестируя этот фреймворк.
C помощью Snap я создал небольшой демонстрационный проект, который я представляю по ходу текста. Местами в тексте будет встречаться дословный перевод документации.
Официальный сайт
Погружение в Snap

Установка snap через cabal

#: sudo cabal update
#: sudo cabal install snap

Настройки параметров системы Ubuntu

Snap хранит свои исполняемые бинарные файлы в папке ~/.cabal/bin (snap к примеру), по этому для удобства их использования в файл ~/.bashrc следует добавить строчку:
PATH=$HOME/.cabal/bin:$PATH

Создание каркаса типового Snap проекта

#: mkdir myproject
#: cd myproject
#: snap init

команда snap init создает шаблон типового проекта в текущей директории.
Сборка проекта:
$: sudo cabal install
Запуск:
#: myproject -p 8000
Теперь по адресу  http://localhost:8000/ должен откликаться созданый сайт.

Файловая структура созданного проекта

dist/
log/
resources/
static/
templates/
src/
Site.hs
Main.hs
Application.hs
Попробую объяснить назначение файлов в папке src
Файл main.hs - это скелет проекта. В файле Application.hs определяется модуль Application, который связан с обработкой ответов сервера и который используется в файле Site.hs. Application.hs используется для расширения стандартного Snap обработчика HTTP запросов. Site.hs - это основной исходный код проекта, роутинг, контроллеры и т.п.
Обработка url адресов в файле Site.hs задается следующим образом:
site :: Application ()
site = route [ ("/",            index)
             , ("/echo/:stuff", echo)
             ]
       <|> serveDirectory "resources/static"

Url адресс "/" относится к функции-обработчику index, "/echo/:stuff" к функции-обработчику echo. Обе эти функции выполняют роли контроллеров.
Фрагмент url адреса отмеченный двоеточием (":") - захватываемое значение параметра stuff. Значение этого параметра можно получить в дальнейшем с помощью rqParams или getParam (как и параметры передаваемые через POST и GET методы).
Вторая половина отделенная от основной части "<|>" будет переправлять на содержимое папки resources/static/.
Дословно оператор "<|>" в монаде Snap означает "try a, and if it fails, try b".
К примеру файл style.css будет искаться в resources/static/. Если он там не найдется метод serveDirectory вынудит Snap выдать ответ "404 Not Found".
Функция/метод/обработчик echo выглядит следующим образом
echo :: Handler App App ()
echo = do
    message <- decodedParam "stuff"
    heistLocal (bindString "message" (T.decodeUtf8 message)) $ render "echo"
  where
    decodedParam p = fromMaybe "" <$> getParam p

Здесь функция decodedParam выступает в качестве обёртки над методом  getParam. В качестве аргумента передается ей имя параметра заданного в роутинге ("stuff"), но можно и передать и имя параметра post при необходимости.
С помощью метода heistLocal используем  полученное значение для построения страницы с помощью шаблона "echo" (render "echo").
А при помощи метода bindString подменяем параметр в шаблоне <message/> на значение (T.decodeUtf8 message).

Snap использует систему шаблонизации Heist. Довольно гибкая и на оф. сайте представлено  достаточно документации.
В предыдущем примере указанный шаблон echo располагается в файле resources/templates/echo.tpl, который представляет из себя html файл с расставленными полями подстановки/параметрами.
Поля подстановки имеют вид ${key} или <key/>
Вот так выглядит шаблон echo:
<html>
<body>
  <div id="content">
    <h1>Is there an echo in here?</h1>
  </div>
  <p>You wanted me to say this?</p>
  <p>"<message/>"</p>
  <p><a href="/">Return</a></p>
</body>
</html>
Усложним типовой проект.
Добавим на главную страницу ("/") форму, которая при отправке данных будет:
  1. сохранять данные в файле -> Вызов монады IO в монаде Snap 
  2. выдавать страницу ответа -> Передача на страницу данных методом POST 
Добавим в файл Site.hs:
import System.IO
import qualified Data.ByteString as BS
...
-- пример на обработку post параметров ($_POST[]) и вызова монады IO из монады Snap (Понадобится чтобы сохранить данные в файл)
command3post :: Handler App App ()
command3post = do
    input_name <- decodedPost "firstname" -- ByteString
    second_name <- decodedPost "secondname"
    liftIO $ appendFile "output.txt" (((T.unpack . T.decodeUtf8. BS.concat ) [input_name, " : " ,second_name])++"\n")
-- Пояснение справа на лево:
-- BS.concat - слияние списка элементов ByteString
-- T.unpack . T.decodeUtf8 - преобразуем ByteString в String
-- appendFile - добавляет строку в файл
-- liftIO - преобразует монаду IO в монаду Snap
    heistLocal (bindString "firstname" (T.decodeUtf8 input_name)) $ render "formrezult"
    where
        decodedPost p = fromMaybe "" <$> getParam p 
А список маршрутов приведем к следующему виду:
routes :: [(ByteString, Handler App App ())]
routes = [ ("/",            index)
         , ("formaction", command3post)
         , ("/echo/:stuff", echo)
         , ("", with heist heistServe)
         , ("", serveDirectory "resources/static")
         ] 
В файл resources/templates/index.tpl добавить
<form method="post" action="formaction">
    <p>First name: <input type="text" name="firstname"/></p>
    <p>Second name: <input type="text" name="secondname"/></p>
    <input type="submit" value="send"/>
</form> 
Создать файл resources/templates/formrezult.tpl
<!DOCTYPE HTML>
<html>
  <head>
    <title>Form request Page</title>
  </head>
  <body>
    <div id="content">
      <h1>Form Rezult</h1>
    </div>
    <p>Thank you <firstname/></p>
    <p><a href="/">Return on main page</a></p>
  </body>
</html>
Вот и все. Проект можно собирать и запускать.
Скачать проект целеком.

Вместо вывода

Snap фреймворк очень напоминает работу с RoR или ASP.Net MVC. Хотя я и не вижу явных преимуществ перед другими фреймворками как на Haskell так и на других ЯП, Snap может пригодиться хаскелоидам. В общем дело чисто вкусовых предпочтений аудитории.