Главная  /  Правка версии 1  /  Правка версии 2  /   /  Область пользователей

Отличия "Архитектура плагинов" вер. 1 сравн. вер. 2

Содержимое:

<!--toc-->
## Введение
У CppCMS будет полная встроенная поддержка плагинов в готовящейся к выходу версии 1.2,
которая будет выпущена позже в этом году (2012).
Между тем, в CppCMS 1.0 уже есть все основы для поддержки плагинов. Темплейты уже полностью подключаемы (загрузка разделемого объекта и темплейта готова к использованию).
Также есть новый класс booster::shared_object, позволяющий легко загружать динамические библиотеки.
Однако, в зависимости от архитектуры Вашего приложения, выбор точного решения может варьироваться. В следующих разделах будут рассмотрены различные варианты развития событий.
Если здесь ничего не понятно, пожалуйста, спросите об этом в мейл-листе и вернитесь сюда для надлежащего исправления этой страницы.
## Темплейты подключаемые с помощью разделяемого объекта.
У каждого разделяемого объекта темплейта есть глобальный конструктор и деструктор.
Как только разделяемый объект загружен, вызывается конструктор и регистрирует себя в singleton'е cppcms::views::pool, становясь видимым для всех. При выгрузке он разрегистрируется с помощью глобального деструктора и больше не может больше использоваться.
Это простая и прозрачная семантика.
Если плагин связан с кодом темплейта, будет загружаться его собственный темплейт:
Если плагин связан с кодом темплейта, он загрузит собственный темплейт:
libmy_plugin.so
my_application.cpp:
// мой код
{
...
render("my_plugin_skin","some_view",some_content);
}
my_view.cpp <- my_view.tmpl
// этот код генерируется автоматически
namespace {
struct loader {
loader() { cppcms::views::pool::instance().add(my_skin_generator()); }
~loader() { cppcms::views::pool::instance().remove(my_skin_generator());}
} loader_instance;
}
Поэтому, как только вы загрузите разделяемый объект, выполнится loader::loader() и
зарегистрирует view, а когда будете выгружать разделяемый объект - loader::~loader()
разрегистрирует его.
Удостоверьтесь, что у каждого темплейта есть собственное имя skin'а.
## Темплейты с собственным фреймворком плагинов
Если Вы реализовали собственный фреймворк плагинов, есть два метода, позволяющие плагинам определить их собственные темплейты для создаваемого ими контента, интегрируемого в страницу, генерируемую главным приложением.
### Использование потоков
Основное приложение определяет макет всей страницы:
<% skin basic_skin %>
<% view basic_view uses content::basic_content %>
<html>
...
<body>
...
<!--- aux-часть-->
<% foreach p in plugings %>
<% item %><%= p.rendered_aux_html_content | raw %><% end %>
<% end %>
...
<!--- Main-часть-->
<% foreach p in plugings %>
<% item %>
<div id="plugin_<%=p.id %>" >
<%= p.rendered_main_html_content | raw %>
</div>
<% end %>
<% end %>
...
</body>
<% end view %>
...
<% end skin %>
Каждый плагин определяет темплейты для своего собственного содержимого:
<% skin plugin_a %>
<% view main_html uses plugin_a_content::some_content_b %>
<% template render() %>
<!-- Указание render-функции -->
какой-то конкретный html плагина
делающий что-то, что ему нужно
<% end template %>
<% view aux_html uses plugin_a_content::some_content_a %>
<% template render() %>
<!-- Указание render-функции -->
какой-то конкретный html плагина
делающий что-то, что ему нужно
<% end template %>
<% end view %>
<% end skin %>
Предположим, что наш плагин должен предоставлять следующее API:
class plugin {
public:
virtual std::string main_html(cppcms::applicatin *app) = 0;
virtual std::string aux_html(cppcms::application *app) = 0;
};
Содержимое каждого плагина рендерится примерно так:
// main_application.cpp
content::basic_content c;
// подготавливаем c
...
// рендерим плагины
for(int i=0;i<loaded_plugins.size();i++) {
c.plugins[i].rendered_main_html_content = loaded_plugins[i]->main_html(this);
c.plugins[i].rendered_aux_html_content = loaded_plugins[i]->aux_html(this);
}
render("basic_skin","basic_view",c);
На стороне плагина, это выглядит примерно так:
std::string main_html(cppcms::applicatin *app)
{
plugin_a_content::some_content_b c;
...
std::ostringstream buf;
app->render("plugin_a","main_html",c,buf);
return buf.str();
}
std::string aux_html(cppcms::applicatin *app)
{
plugin_a_content::some_content_a c;
...
std::ostringstream buf;
app->render("plugin_a","aux_html",c,buf);
return buf.str();
}
### С помощью команды 'render'
Начиная с CppCMS 0.99.12 есть команда <% render ... %> См. [Рендеринг других view](wikipp/en/page/cppcms_1x_templates_comm#Rendering.other.views).
Основное приложение определяет макет всей страницы:
<% skin basic_skin %>
<% view basic_view uses content::basic_content %>
<html>
...
<body>
...
<!--- aux-часть-->
<% foreach p in plugings %>
<% item %><% render p->name(), "aux_html" with p->aux_html_content() %><% end %>
<% end %>
...
<!--- Main-часть-->
<% foreach p in plugings %>
<% item %>
<div id="plugin_<%=p->id() %>" >
<% render p->name(), "main_html" with p->main_html_content() %>
</div>
<% end %>
<% end %>
...
</body>
<% end view %>
...
<% end skin %>
, где p - указатель на объект плагина.
Темплейт плагина будет реализовываться как и в предыдущем разделе. См. выше.
Предположим, что наш плагин должен предоставлять следующее API:
class plugin {
public:
virtual void prepare() = 0;
virtual cppcms::base_content &main_html_content() = 0;
virtual cppcms::base_content &aux_html_content() = 0;
virtual std::string name() = 0;
};
Содержимое каждого плагина рендерится примерно так:
basic_content {
...
// указатели на плагины
std::vector<plugin *> plugins;
}
main_application.cpp:
content::basic_content c;
// подготавливаем c
...
for(p in plugins)
p->prepare();
render("basic_skin","basic_view",c);
На стороне плагина, это выглядит примерно так:
class my_plugin : public plugin {
public:
virtual void prepare()
{
... установки main_ и aux_...
}
virtual std::string name() { return "plugin_a"; }
virtual cppcms::basic_content &main_html_content() { return main_; }
virtual cppcms::basic_content &aux_html_content() { return aux_; }
private:
plugin_a_content::some_content_b aux_;
plugin_a_content::some_content_a main_;
};
std::string main_html(cppcms::applicatin *app)
{
plugin_a_content::some_content_b c;
...
std::ostringstream buf;
app->render("plugin_a","main_html",c,buf);
return buf.str();
}
std::string aux_html(cppcms::applicatin *app)
{
plugin_a_content::some_content_a c;
...
std::ostringstream buf;
app->render("plugin_a","aux_html",c,buf);
return buf.str();
}
### Вариации
Вариации на базе вышеуказанного, в зависимости от нужд Вашего приложения.
Определение плагина:
plugin {
void render_main(cppcms::application &);
void render_aux(cppcms::application &);
}
, где плагин выполняется как:
render_main(cppcms::application &app)
{
app.render("plugin_a","main_html",my_content);
}
и темплейт выглядит как:
<% foreach p in plugins %>
<% item %>
<% c++ p->render_main(content.app()); %>
<% end item %>
<% end foreach %>
## Повторное использование skin'а
В этом разделе рассматривается возможность плагина по повторному использованию skin'а, осуществляющаяся ядром приложения.
Предположим, что Ваш плагин хочет расширить basic_skin::basic_view (т.е. наследоваться от них) и иметь контроль над всей страницей.
Это намного хитрее.
Вы не можете наследоваться от них, т.к. cppcms_tmpl_cc не генерирует заголовочные файлы.
Вместо этого, сделайте следующее.
Вместо записи: <% skin basic_skin %>, используйте неименованный skin: <% skin %>
Затем скомпилируйте основной skin:
Main view cpp:
cppcms_tmpl_cc -s basic_skin basic_view.tmpl some_other_main_views.tmpl -o basic_skin.cpp
g++ basic_skin.cpp -o libbasic_skin.so
cppcms_tmpl_cc -s plugin_a basic_view.tmpl plugin_a.tmpl -o plugin_a.cpp
g++ plugin_code.cpp plugin_a.cpp -o libplugin_a.so
Обратите внимание, что basic_view.tmpl присутствует дважды, первый - под skin'ом=namespace, а второй раз - под skin'ом=namespace plugin_a.
Это дублирует c++-код и требует от плагина действительно использовать код skin'а приложения.
Это не идеально, но терпимо, по крайней мере пока cppcms_tmpl_cc не станет поддерживать генерацию файлов .h и .cpp.

Проект

CppCMS является основой веб-разработки для выполнения ресурсоемких приложений.

Размещение

SourceForge.net Logo

Поддержать проект

CppCMS needs You


Навигация

Главная страница


Валидация CSS | Валидация XHTML 1.0