Skip to content

MelisEngine

共享的 CMS 数据基础——页面模型、站点、语言、模板插件基类以及渲染缓存。软件包 melisplatform/melis-engine

用途

MelisEngine 拥有整个 CMS 数据库模型(页面、页面树、站点、模板、语言、域名、SEO、样式),并通过表网关、服务和多层缓存对外暴露。MelisFront(前端渲染)和 MelisCms(后台编辑)都只能通过 MelisEngine 进行读写——两个同级模块本身都不拥有任何数据表。它同时定义了 MelisTemplatingPlugin,即平台中每个内容插件所继承的抽象基类。

在 React 后台中的角色

MelisEngine 没有 React 后台工具,也没有自己的 UI——没有 brick,没有 config/react-api.php,没有能力(capabilities),在 /melis-react 中也没有侧边栏入口。它没有迁移到 React,并且也不打算迁移:它是平台基础设施,而非后台工具。它与 React 外壳的关系完全在幕后进行,分为两条路径:

  • 数据路径——React CMS 控制器(MelisReactApi*,它们位于 CMS 模块中,而非本模块中)通过 MelisEngine 的 MelisEngineTable* 网关和服务(MelisEnginePageMelisEngineTreeMelisEngineLang 等)读写页面、站点、语言、模板和 SEO。React 层从不直接接触 CMS 模式(schema)。
  • 渲染路径——在 React 页面编辑器和旧版 iframe 工具中展示的 CMS 内容是在服务端渲染的(页面 → 模板 → 区域 → 插件)。引擎负责解析页面模型并定义插件基类;MelisFront 执行实际的渲染。React 嵌入服务端渲染的结果,而不是在客户端重新渲染 CMS 内容。

由于它虽不可见但却是承重的,引擎问题会在 React CMS 工具内部显现出来——空白的页面树、始终为空的语言下拉框、加载时报错的页面编辑器——这些通常由缺失/滞后的 CMS 表或某个失效的引擎服务引起,而绝非由某个引擎界面引起(因为根本没有引擎界面)。

启用它

MelisEngine 作为依赖被自动加载。在 config/melis.module.load.php 中的加载顺序为:

php
// config/melis.module.load.php
return [
    'MelisCore',
    'MelisFront',
    'MelisEngine',   // requires melis-core + melis-front
    'MelisCms',
];

Composer 依赖:melisplatform/melis-core ^6.0melisplatform/melis-front ^6.0laminas/laminas-cache(filesystem + memory 适配器)。运行于 PHP ^8.3 | ^8.5

核心服务

config/module.config.php 中注册为 service_manager 别名:

服务别名角色
MelisEnginePage / MelisPageService按 id 和模式(published / saved)解析页面:getDatasPage($idPage, $mode)——返回已填充的页面树、页面数据、SEO、模板和样式对象
MelisEngineTree / MelisTreeService页面树导航:getPageChildren()getPageFather()getPageBreadcrumb()getPageLink()、搜索
MelisEngineTemplateService模板查询:getTemplate($tplId)
MelisEngineSiteService站点目录
MelisEngineSiteDomainService域名 → 站点解析:getSiteByDomain()
MelisEngineLang / MelisEngineLangService语言:可用语言、locale ↔ id、站点语言
MelisEngineSEOService单页 SEO 数据:getSEOById()
MelisEnginePageDefaultUrlsService预计算 / 规范页面 URL 查询
MelisEngineStyle / MelisEngineStyleService站点样式和单页 CSS
MelisEngineCacheSystem缓存编排器:getCacheByKey()setCacheByKey()deleteCacheByPrefix()
MelisSearch供前端搜索使用的全文(Lucene 风格)页面索引
MelisEngineSendMail邮件工具
MelisGdprService / MelisGdprAutoDeleteServiceGDPR 横幅文本及自动删除框架
MelisEngineComposerComposer / 依赖操作

所有继承 MelisGeneralService 的服务都会触发 *_start / *_end 事件(例如 melisengine_service_get_available_languages_start / _end),其他模块可以挂接这些事件。

React 消费方(已验证)

以下是 React CMS 工具通过引擎调用的官方数据路径入口点:

引擎服务 / 网关(别名)使用方(React 后台)
MelisEnginePage (MelisPageService)melis-cms MelisReactApiPageController——为 React 页面编辑器提供页面数据
MelisEngineTree (MelisTreeService)melis-cms MelisReactApiPageController——页面树导航
MelisEngineLang (MelisEngineLangService)melis-cms MelisReactApiCmsSitesControllerMelisReactApiCmsMenuManagerController——可用的 CMS 语言
MelisEngineTableCmsLang (MelisCmsLangTable)melis-cms-tags、melis-cms-user-account、melis-core(GDPR)——React 语言下拉框

别名 MelisEngineTableCmsLang => MelisCmsLangTable::class 注册于 config/module.config.php 中。

后台

MelisEngine 无论是在旧版后台还是在 /melis-react 中,都没有自己面向最终用户的工具。它注册了两个在整个后台中使用的表单元素工厂:

工厂用途
MelisEnginePluginTemplateSelect用于插件表单的模板选择元素
MelisEngineSiteSelect用于插件表单的站点选择元素

安装与维护控制器(MelisSetup*)也存在,但它们由安装程序调用,而非由编辑者调用。

前台

每个内容插件的基类都位于此处:

描述
MelisEngine\Controller\Plugin\MelisTemplatingPlugin所有内容插件的抽象基类。定义了 front()(实时渲染,抽象方法)、back()(后台容器/编辑视图)、配置 XML 持久化(loadDbXmlToPluginConfig() / savePluginConfigToXml())、GET/POST 加载、预览模式和响应式宽度。

每个平台内容插件(News、Slider、Menu、Breadcrumb 等)都继承此类。实现 front() 以进行实时输出;基类会自动处理 back()。同一条插件流水线也为 React 页面编辑器提供支持:MelisFront 在服务端渲染每个区域的插件,React 显示其结果。

两个微服务监听器挂接 melis_core_microservice_amend_data,以便通过平台微服务层暴露页面树和页面方法(getPageChildrengetPageFathergetDomainByPageIdgetDatasPage)。

数据库表

MelisEngine 是 CMS 模式的唯一可信来源(install/sql/setup_structure.sql + install/dbdeploy/ 增量):

存储内容
melis_cms_page_tree页面层级(tree_father_page_id、顺序)
melis_cms_page_published每个页面的已发布(线上)版本
melis_cms_page_saved已保存 / 草稿版本(在后台中编辑)
melis_cms_page_lang页面 ↔ 语言关联
melis_cms_langCMS 语言 / locale
melis_cms_site站点(页面树的根)
melis_cms_template模板(布局 / 控制器 / 动作或 PHP 路径)
melis_cms_page_seo单页 SEO(URL、301 重定向、meta 标题/描述、canonical)
melis_cms_site_domain各环境下的站点域名
melis_cms_site_301 / melis_cms_site_404站点级 301 重定向 / 404 映射
melis_cms_page_default_urls预计算的页面 URL(缓存表)
melis_cms_style / melis_cms_page_styleCSS 样式和页面 ↔ 样式关联
melis_cms_platform_ids各环境下的页面 id 分配区间
melis_cms_site_config / _home / _langs站点配置、各语言的首页、启用的语言
melis_cms_site_robot各域名的 robots.txt
melis_cms_mini_tpl_*迷你模板分类、模板和标志
melis_cms_gdpr_texts各站点 / 语言的 GDPR 横幅文本
melis_site_translation / _text站点级翻译字符串

表网关

每个表都由一个在服务管理器中注册的 MelisEngineTable* 网关封装(例如 MelisEngineTablePageTreeMelisEngineTablePagePublishedMelisEngineTablePageSeo)。其他模块——无论是旧版还是 React——都必须始终使用这些网关,绝不能使用原始 SQL。基础网关提供 getEntryById()getEntryByField()save()deleteById()fetchAll()

示例

读取一个页面并遍历页面树:

php
$pageSvc = $sm->get('MelisEnginePage');
$page    = $pageSvc->getDatasPage($idPage);            // 'published' (live) by default
$draft   = $pageSvc->getDatasPage($idPage, 'saved');   // draft shown in the React page editor

$tree       = $sm->get('MelisEngineTree');
$children   = $tree->getPageChildren($idPage, 1);       // 1 = published only
$breadcrumb = $tree->getPageBreadcrumb($idPage);
$url        = $tree->getPageLink($idPage, true);        // true = absolute URL

从 CMS 控制器填充 React 语言下拉框(服务端,委托给引擎):

php
// Inside a MelisReactApi* controller of a CMS module — the React JSON layer
// delegates to the engine; MelisEngine exposes no react-api of its own.
$langTable = $sm->get('MelisEngineTableCmsLang');
$langs     = $langTable->fetchAll()->toArray();   // fills a React language dropdown

通过表网关读写(绝不使用原始 SQL):

php
$seoTable = $sm->get('MelisEngineTablePageSeo');
$seo      = $seoTable->getEntryByField('plang_page_id', $idPage)->current();
$seoTable->save(['seo_meta_title' => 'New title'], $existingSeoId);  // upsert

缓存一个计算结果:

php
$cache = $sm->get('MelisEngineCacheSystem');
$cache->setCacheByKey('mykey', 'my_cache_config', $value);
$value = $cache->getCacheByKey('mykey', 'my_cache_config');
$cache->deleteCacheByPrefix('page_' . $idPage, 'meliscms_page');   // invalidate a page

监听一个服务事件:

php
$sharedEvents->attach('MelisEngine', 'melisengine_page_getdatas_end', function ($e) {
    $p = $e->getParams();   // includes page id and 'results'
    // alter $p['results'] before it is returned
}, 50);

构建一个内容插件:

php
// Subclass MelisTemplatingPlugin, implement front() for live render.
// The base class handles back() (BO container), config XML persistence and preview.
class MyPlugin extends MelisEngine\Controller\Plugin\MelisTemplatingPlugin
{
    public function front(): string
    {
        return $this->getView()->render('my-module/plugin/my-plugin', $this->pluginConfig);
    }
}

Core / Engine / Front 三件套

React 后台并未改变这个三件套;它构建于其之上:

  • MelisEngine (本模块)——拥有整个 CMS 数据库模型,并通过表网关 + 服务 + 缓存对外暴露;定义 MelisTemplatingPlugin
  • MelisFront——根据引擎的数据渲染页面(运行内容插件),并为后台内部使用的可编辑预览提供支持(旧版以及 React 页面编辑器 / iframe 工具)。
  • MelisCms——CMS 后台;它不拥有任何表,一切都通过引擎进行编辑。它的 React CMS 工具(MelisReactApiPageMelisReactApiCmsSitesMelisReactApiCmsMenuManager 等)就是上面列出的 React 消费方。

关键文件

关注点路径
服务与网关别名、缓存vendor/melisplatform/melis-engine/config/module.config.php
页面数据服务vendor/melisplatform/melis-engine/src/Service/MelisPageService.php
页面树 / 链接服务vendor/melisplatform/melis-engine/src/Service/MelisTreeService.php
缓存编排器vendor/melisplatform/melis-engine/src/Service/ (MelisEngineCacheSystem*)
模板插件基类vendor/melisplatform/melis-engine/src/Controller/Plugin/MelisTemplatingPlugin.php
表网关vendor/melisplatform/melis-engine/src/Model/Tables/
模式 + 增量迁移vendor/melisplatform/melis-engine/install/sql/

另请参阅:MelisFront · MelisCms · MelisCore