1

Тема: [Релиз] Разработка расширения "Developer Helper"

Привет всем, кто читает тему.
Разговор пойдет о создании расширения "Developer Helper", предполагается, что читатель - разработчик расширений для punbb, поэтому если это не так, то читать дальше смысла нет.

Выявление проблемы
Разные расширения  по разному решают проблемы, решением которых по сути должно заниматься ядро. Например обеспечение доступа к глобальным переменным. Типичное решение в функции - объявление globals. Где-то в сети мне попадались исследования, свидетельствующие о том, что этот путь медленнее доступа к статическому свойству класса.
Ядро форума не дает возможности осуществлять роутинг к контроллерам. Например некое расширение желает использовать путь из запроса GET  для запуска соответствующего контроллера: misc.php?r=myextension/foo/bar , а нужного механизма нет.

Решение
Для доступа из любого места в коде к глобальным переменным, например 
$forum_db, $forum_user, $forum_page, $forum_url, $forum_hooks вводим класс (например App) с одноименными статическими свойствами, инициализируемыми как ссылки на эти глобальные переменные.
В хуке es_essentials этот класс подключается и инициализируется.
Теперь любое расширение, явно зависимое от  Developer Helper может в своих  функциях и классах получить доступ к глобальной переменной без предварительного объявления через globals например: App::$forum_user['is_guest']

Второй момент - роутинг.
Расширение явно зависимое от  Developer Helper может использовать соглашение о роутинге, т.е. если в запросе misc.php? есть параметр r, то Developer Helper попытается его обработать исходя из предположения, что r - это путь к контроллеру какого-либо расширения, например misc.php?r=myextension/foo/bar означает расширение myextension, класс контроллера foo метод контроллера bar. Для реализации этого механизма, в хуке mi_new_action вызывается например App::route();, в котором эта магия и реализована. При этом не нужно изобретать велосипед, магия копируется с небольшими изменениями из yii или kohana

Можно пойти дальше, реализовать autoload классов, хелперы для вывода html тегов, кеширование, инъекции кода в хуки в рантайм, без манифестов и т.п.

Какие из всего этого плюсы? Стандартизация, упрощение разработки, использование ООП + MVC и тп.
Интересует ли такой вектор развития кого-нибудь, желает ли кто-то присоединиться словом и делом? Может есть весомые аргументы против?

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

2

Re: [Релиз] Разработка расширения "Developer Helper"

Предлагаю посмотреть как это работает: http://punbb.ru/downloads/development.zip
Архив содержит два расширения Developer helper и Developer test для его демонстрации.
Пример добавляет пункт навигационного меню средствами хелпера, обработка пункта осуществляется хелпером, т.к. ссылка построена на соглашении роутинга. Так же реализована автозагрузка классов и пример демонстрирует это тоже.
Смотрите код примера. Высказывайтесь.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

3

Re: [Релиз] Разработка расширения "Developer Helper"

Забавно конечно писать расширения используя mvc и ооп, для движка который полностью написан на процедурном программировании smile
Идея в принципе интересная, но область применения на сколько я вижу в основном - это дописывание большого количества изменений и дополнений в работу форума, в то время как мне кажется основная часть уже существующих расширении - это незначительная модификация существующих страниц. Можно конечно использовать и предложенный способ, но основные изменения в расширениях выглядят достаточно банально:

  • нахождение нужной строки

  • ее незначительные изменения (например скрытие даты регистрации под аватаром пользователя из viewtopic)

  • оформление этого всего в нужном виде (манифест или хук(и) для anycode)

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

Поделиться

4

Re: [Релиз] Разработка расширения "Developer Helper"

Спасибо что откликнулся.
Речь о серъёзных расширениях. MVC предлагается для обработки входа в скрипт, его использование необязательно, но при использовании облегчает задачу разработки и минимизирует телодвижения (скелет уже готов). Одно действие - одна функция, а не как сейчас - бесконечное ветвление с мыслимыми и немыслимыми условиями:

if ($action = 'blablabla')
{
} 
elseif  ($section = 'blabla') 
{
...
}
else
{ }


Эта сумасшедшая лапша накладывает отпечаток на сознание разработчиков, в результате и расширения получаются такие же. В случае с ЛС все немного лучше, там есть много функций smile
К появлению такого "склеивающего" расширения меня подтолкнула разработка системы оплаты и расширения платных услуг. Если каждое расширение будет своим способом решать задачу быстрого доступа к глобальным переменным и обработки входящих запросов, то получится дублирование действий. Каждое расширение в misc.php добавит свое условие, $actions начнут повторяться, конфликтовать и т.п.
Ктстати ООП в процедурном ядре присутсвует в виде абстрактного слоя работы с БД. Вещь очень удобная и мощная.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

5 (09.02.2011 05:38 отредактировано Griffon)

Re: [Релиз] Разработка расширения "Developer Helper"

Да я немного работал с zend framework и codeigniter, и с принципами mvc предлагаемыми ими немного знаком (я думаю с yii и kohana они достаточно похожи).
Если говорить про роутинг, то по минимуму я думаю стоит ввести понятие default controller, для не очень больших проектов не требующих более 1 контроллера и вместо misc.php?r=myextension/controller/action позволить использовать короткую форму misc.php?r=myextension/controller, а так же index action, с совсем короткой записью типа misc.php?r=myextension

Добавлено спустя 1 минуту 28 секунд:

как то так:

        if (!isset($_GET['r']))
            return false;

        $params = explode('/',preg_replace('/[^a-zA-Z0-9\-_\/]/','',$_GET['r']));
        unset($_GET['r']);

        $route['extenstion'] = array_shift($params);
        $route['controller'] = 'default';
        $route['action'] = 'index';
        $route['arguments'] = '';

        if (count($params) > 1)
        {
            $route['controller'] = array_shift($params);
            $route['action'] = array_shift($params);
            if (count($params) > 0)
                $route['arguments'] = $params;
        }
        else
            $route['controller'] = array_shift($params);

        var_dump($route);

        $controller = FORUM_ROOT.'extensions'.DIRECTORY_SEPARATOR.$route['extenstion'].DIRECTORY_SEPARATOR.'controllers'.DIRECTORY_SEPARATOR.$route['controller'].'.php';

        if (!file_exists($controller) && defined(FORUM_DEBUG))
            message('Invalid controller '.forum_htmlencode($controller));
        else
            return false;

        require $controller;

        self::$controller_instance = new $route['controller'];

        if (method_exists(self::$controller_instance, $route['action']))
                call_user_func_array(array(self::$controller_instance, $route['action']), $route['arguments']);
        elseif(defined(FORUM_DEBUG))
            message('Invalid action <strong>'. forum_htmlencode($route['action']).'</strong> on controller '.forum_htmlencode($controller));
        else
            return false;

Добавлено спустя 20 минут:

По поводу автолоадинга, я правильно понял что класы засунутые в автолоад, будут подключатся при генерации любой страницы?

Поделиться

6

Re: [Релиз] Разработка расширения "Developer Helper"

Честно говоря не дошел до дефолтовых контрллеров и экшенов по причине лени, хотя твоя реализация получилась лаконичнее и более понятна. Я вижу тебя тема "зацепила" smile

Добавлено спустя 8 минут 6 секунд:

Griffon пишет:

По поводу автолоадинга, я правильно понял что класы засунутые в автолоад, будут подключатся при генерации любой страницы?

Нет. Класс в автолоадинге будет подключен в момент первого обращения к нему.

Добавлено спустя 8 минут 49 секунд:

Насколько я понимаю документацию к пхп...

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

7

Re: [Релиз] Разработка расширения "Developer Helper"

ага, уже пару ошибок нашел, а папочку controller на автопилоте переименовал в controllers
все понял как автолоадер фурычит, имхо не совсем удобно так выходит. по сути сама регистрация класса не нужна, если привести имя загружаемого класса к какому либо виду, который в последствии можно распарсить, например Extension_Controller_Class или Extension_Model_Class ну и тому подобное, как это сделано в zend framework, это уберет лишний код и упростит их подключение

Поделиться

8

Re: [Релиз] Разработка расширения "Developer Helper"

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

Добавлено спустя 6 минут 55 секунд:

Но при таком подходе становится затруднительно использовать короткое название класса.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

9

Re: [Релиз] Разработка расширения "Developer Helper"

в общем то это имя и нужно то всего разок скормить конструктору а потом называй его как душе угодно, зато сразу становится понятно про какое расширение идет речь

Поделиться

10

Re: [Релиз] Разработка расширения "Developer Helper"

hcs пишет:

Честно говоря не дошел до дефолтовых контрллеров и экшенов по причине лени

Посмотрел повнимательней и вспомнил настоящую причину отсутствия дефолтовых контроллеров и экшенов.
Мы можем захотеть поместить контроллер глубже в папке controller, например в папку user:
my_extension/user/controller/action
А то  и глубже. В таком случае у нас контроллером станет имя папки, а экшеном имя контроллера, что задачу не решает. Я не думаю, что принуждение указывать контроллер и экшн, даже если он дефолтовый, негативно скажется на разработчике и процессе разработки. Максимум пострадает внешний вид ссылки, но как правило на рабочих форумах включен реврайт, поэтому такая ссылка будет скрыта (если того пожелает разработчик). Дополнительный плюс - при просмотре ссылкив процессе разработки понятно что это и куда ведет, т.е. поведение ожидаемое, не нужно тратить лишнюю эээ психическую энергию и время на интерпретацию.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

11

Re: [Релиз] Разработка расширения "Developer Helper"

По моему ты усложняешь, подпапки - это своего рода аналог модульной структуры, но использовать модули в расширениях понадобится только в очень крупном расширении, я такую ситуацию я себе представить не могу например, зато ссылки вида extension/controller/action/some/other/stuff дают возможность из коробки передать всю оставшуюся строку в виде параметров action'у в виде строки (some/other/stuff) или нумерованного массива ([0]=>"some", [1]=>"other", [2]=>"stuff"), а так же создать единое правило для rewrite'а, позволяющее не вспоминать о них разработчикам. Это же helper, в конце концов, он должен помогать и упрощать, а не давать возможность написать новый форум на ооп

Поделиться

12

Re: [Релиз] Разработка расширения "Developer Helper"

Подпапки просто способ структуризации хранения файлов. Если это и есть модульная структура, то пусть модульная структура. Логично же контроллеры относящиеся к админке расположить например в подпапке admin? Исключительно с целью структуризации и отделения мух от котлет.
Конечно можно обойтись соответствующими названиями файлов классов, типа amin_index.php, user_index.php и т.д
А какое единое правило для реврайта ты предлагаешь?

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

13

Re: [Релиз] Разработка расширения "Developer Helper"

hcs пишет:

Логично же контроллеры относящиеся к админке расположить например в подпапке admin?

Возможно, но сколько ты разработал расширений за последний год которые могли бы потребовать хотя бы 2х контроллеров для админки? Я конечно понимаю что можно рисовать в каждом контроллере по экшену и наклепать таким способом с десяток контроллеров, но какова реальная необходимость такого размазывания?

hcs пишет:

А какое единое правило для реврайта ты предлагаешь?

Банально завернуть все как нибудь так: my_site.ru/extension/my_extension/my_controller/my_action/misc

Поделиться

14

Re: [Релиз] Разработка расширения "Developer Helper"

Griffon пишет:

Возможно, но сколько ты разработал расширений за последний год которые могли бы потребовать хотя бы 2х контроллеров

Убедил

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

15

Re: [Релиз] Разработка расширения "Developer Helper"

Проблема из-за именований классов такого плана:
У нас есть расширение my_extension, с подчеркиванием
В расширении есть некий класс, название которого должно отражать суть, т.е. название должно содержать например my_class
Класс вспомогательный, поэтому расположен прямо в корне расширения.
Исходя из соглашения об именовании классов мы должны его назвать
My_extension_my_class
Теперь автолоадер получив такое имя, будет искать класс с именем class в папке ./extensions/my/extension/my
в то время как он находится в ./extensions/my_extension/
Какие есть идеи?

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

16

Re: [Релиз] Разработка расширения "Developer Helper"

Ну для начала неплохо бы типизировать какие классы вообще могут быть, например:

  • контроллеры

  • модели

  • еще может что-то понадобится

и как вариант разделить имя расширения и имя класса типом класса, например: My_extenstion_Controller_My_class, отлавливая его в названии класса, и разделяя по нему части, однозначно определяя путь к my_extension/controllers/my_class.php, правда придется наложить вето на использование некоторых слов в названиях классов

Поделиться

17

Re: [Релиз] Разработка расширения "Developer Helper"

Сделал новый вариант, учитывающий новые соглашения.
Теперь возникает досадная мелочь, есть класс Developer_test_Module_Dev_test_class
имеющий статический метод, например test.
Мы очень удобно можем к этому классу обратится, не беспокоясь о его подключении, но навязанное нам его имя, и обращение к статическим методам это полный швах:

Developer_test_Module_Dev_test_class::test();

Все понятно, что за класс, откуда, но как же это длинно! smile

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

18

Re: [Релиз] Разработка расширения "Developer Helper"

По ссылке сверху код не изменился.
На сколько я понимаю модель MVC, основная работа со всем чем можно идет внутри контроллера, а точнее внутри конкретного экшена, который был вызван, соответственно чаще всего ты будешь использовать конструкции аля $this->do_something, $this->do_something_else и тому подобные. Ну а зачем тебе понадобились статические методы, да еще и так часто что бы запариваться по поводу длинны названия функции, я пока догадаться не смог если честно

Поделиться

19

Re: [Релиз] Разработка расширения "Developer Helper"

Я новый вариант не выкладывал пока.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

20

Re: [Релиз] Разработка расширения "Developer Helper"

Обновил версию: http://punbb.ru/downloads/developer_helper.zip
1. Реализовано соглашение об именовании:
Названия классов, претендующих на автоматическую загрузку  должны именоваться
Имя_расширения_Имя_папки_Имя_класса, где Имя_папки может быть одним из:
Controller, Model, Module, View
Имя_класса должно совпадать с именем файла, в котором этот класс находится.
2. Добавлена загрузка языковых файлов. Языковой файл немного отличается от обычного и должен возвращать массив, а не объявлять:

return array (
'lang string' => 'перевод'
);

Загрузка файла может происходить где угодно и сколько угодно раз таким образом:

App::load_language('Имя_расширения');

При такой записи будет загружаться файл Имя_расширения/lang/English.php
Если языковых файлов у расширения несколько и они сгруппированы в папке с именем языка, то загрузку делать так:

App::load_language('Имя_расширения.Имя_файла');

Имя_файла - без расширения.
Загружать можно сколько угодно языковых файлов, доступ к языковым переменным:

App::$lang['lang string']

3. Введено 3 вида роутинга - к админ-центру, к профилю, ко всему остальному.
Сделано это потому, что для профиля шапка и меню формируется в profile.php, для админки шапка и меню -  во вложенной папке admin (в нашем случае для админки обработчик находится в admin/settings.php),  а для других случаев все стандартно иоднотипно, поэтому обработчик в misc.php.
С точки зрения формирования ссылок это выглядит так:

profile.php?section=route&id=$1&r=расширения/класс/действие
admin/settings.php?section=route&r=расширения/класс/действие
misc.php?section=route&r=расширения/класс/действие

Обратите внимание, что для профиля мы должны передать ид пользователя ($1)
Если придерживаться такого разделения, то  для профиля хелпер подготовит crumb :

Имя форума> Имя пользователя

для админки:

Имя форума> Администрирование

в контроллере останется только доформировать свои крошки, например:

App::$forum_page['crumbs'][] = array(App::$lang['Section billing'],forum_link(App::$forum_url['profile_billing'], App::$forum_user['id']));

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

Примера пока нет, извиняйте.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

21

Re: [Релиз] Разработка расширения "Developer Helper"

hcs пишет:

Обновил версию: http://punbb.ru/downloads/developer_helper.zip
1. Реализовано соглашение об именовании:
Названия классов, претендующих на автоматическую загрузку  должны именоваться
Имя_расширения_Имя_папки_Имя_класса, где Имя_папки может быть одним из:
Controller, Model, Module, View
Имя_класса должно совпадать с именем файла, в котором этот класс находится.

А зачем нужны модули?

hcs пишет:

2. Добавлена загрузка языковых файлов. Языковой файл немного отличается от обычного и должен возвращать массив, а не объявлять:

return array (
'lang string' => 'перевод'
);

Загрузка файла может происходить где угодно и сколько угодно раз таким образом:

App::load_language('Имя_расширения');

При такой записи будет загружаться файл Имя_расширения/lang/English.php
Если языковых файлов у расширения несколько и они сгруппированы в папке с именем языка, то загрузку делать так:

App::load_language('Имя_расширения.Имя_файла');

Имя_файла - без расширения.
Загружать можно сколько угодно языковых файлов, доступ к языковым переменным:

App::$lang['lang string']

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

Поделиться

22

Re: [Релиз] Разработка расширения "Developer Helper"

Модули нужны для модулей. Не могу пока объяснить, я же этот хелпер делаю не абстрактно и оторванно от жизни, а совместно с расширением от него зависимого. Вкратце, там есть классы, не имеющие отношения к контроллерам. Логично их отделить.
По языку, загружается тот язык, который в профиле.
Фактически это аналог такой конструкции, которую прописывают в хуках:

        if (file_exists($ext_info['path'].'/lang/'.$forum_user['language'].'/'.$ext_info['id'].'.php'))
            include $ext_info['path'].'/lang/'.$forum_user['language'].'/'.$ext_info['id'].'.php';
        else
            include $ext_info['path'].'/lang/English/'.$ext_info['id'].'.php';
Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться

23

Re: [Релиз] Разработка расширения "Developer Helper"

hcs пишет:

Модули нужны для модулей. Не могу пока объяснить, я же этот хелпер делаю не абстрактно и оторванно от жизни, а совместно с расширением от него зависимого. Вкратце, там есть классы, не имеющие отношения к контроллерам. Логично их отделить

Честно говоря пока не могу себе представить, может на примере?

Добавлено спустя 1 минуту 2 секунды:

hcs пишет:

Фактически это аналог такой конструкции, которую прописывают в хуках:

        if (file_exists($ext_info['path'].'/lang/'.$forum_user['language'].'/'.$ext_info['id'].'.php'))
            include $ext_info['path'].'/lang/'.$forum_user['language'].'/'.$ext_info['id'].'.php';
        else
            include $ext_info['path'].'/lang/English/'.$ext_info['id'].'.php';

В код пока не заглядывал, писал просто по описанию, в общем то оно и имелось в виду roll

Поделиться

24

Re: [Релиз] Разработка расширения "Developer Helper"

Эту тему надо прилепить, а моё сообщение удалить.

Не забываем ставить плюсики дополнительно к «спасибам».

Поделиться

25

Re: [Релиз] Разработка расширения "Developer Helper"

Новая версия 1.0.0.3: http://punbb.ru/downloads/developer_helper.zip
Исправлены небольшие косяки, добавлены новые.
Недавно обнаружил проблему. Если какое-то расширение добавляет глобальную переменную, которая обрабатывается в последствии в хуке в header.php, то она становится неопределенной, потому что хелпер подключает header.php  в своей области видимости.
Есть 3 пути:
1) вручную править helper при обнаружении ошибок, добавляя globals соответствующих переменных;
2) принудить разработчиков расширений использовать какую-то системную глобальную переменную, например $forum_page['user_variables'] для хранения значений, которые должны "жить" дольше, чем в одном хуке;
3) импорт всех переменных из $GLOBALS в область видимости хелпера, тогда никто ничего не заметит, но в хелпер попадет вообще всё - кэш банов, кэш хуков и тд.
Я сделал в виде варианта №3, конечно там импортируются ссылки, а не создаются копии, тем не менее эта операция наверное отнимает больше времени.

Примера пока нет. Думаю, что перепишу какое-нибудь расширение с использованием dev_helper, он станет хорошим примером.

Недостатки, отмеченные на текущий момент:
1) если расширение отключено, хелпер будет продолжать осуществлять роутинг к нему. При этом может возникнуть нехорошая ситуация, т.к. хуки этого отключенного расширения не выполняются. Мыслей как проверять расширения на их "включенность" и прекращать их обслуживание пока нет. Возможно само расширение должно контролировать свою "включенность".
2) В контроллере расширения, использующего хелпер, может быть публичный метод, вызов которого извне, т.е. средствами роутинга, нежелателен или даже опасен. Пока нет средств защиты от этого. На практике в других фреймворков используют префиксную нотацию имен методов. Например если публичный метод имеет префикс "_", то роутер не будет обслуживать такой метод. Это хороший вариант и скоро нечто такое появится. А пока рекомендуется просто не создавать публичные методы в контроллере кроме участвующих в роутинге.

Добавлено спустя 12 минут 5 секунд:

зы.

забыл сказать, что изменилась передача параметров. теперь параметры в запросе передаются парой с идентификатором:
ext/controler/action/param1/value1/param2/value2
При этом в контроллере будут созданы соответствующие переменные param1 и param2, доступ к которым будет такой: $this->param1 и т.п.
Разработчику надо следить, чтобы имена передаваемых параметров не совпадали с объявленными свойствами в классе.

Захочешь — найдешь время, не захочешь — найдешь причину.

Поделиться