如何在 Sulu CMS 中动态创建和更新页面?
How can I create and update pages dynamically in Sulu CMS?
我有以下情况:
- 数据库存储有关房屋的信息(地址、房间数量、建造日期、最后售价等)
- 此数据库是通过无法直接集成到 Sulu 驱动的应用程序中的应用程序(我们称该应用程序为 "backend house app")操作的。我可以通过 API 访问存储的数据,它为我提供 JSON-House-objects 的表示形式。我还可以让该应用程序在创建、更新或删除房屋时启动对 Sulu 驱动的应用程序的某种调用。
- 带有 "house"、"room" 等模板的 Sulu 驱动的应用程序(我们称之为 "frontend house app")连接到不同服务器上的不同数据库。这个 Sulu 驱动的应用程序的网站环境显示带有房间页面的房屋页面,其中一些内容是通过与 "backend house app" 的连接预填充的。其他内容仅存在于 "frontend house app" 的数据库中,如用户评论、室内设计评价等,根据 Sulu 模板的配置方面。
我想要实现的是一种基于"backend house app"activity自动创建、更新和删除"frontend house app"页面的方法.
例如,当在"backend house app"中添加新房子时,我希望它通知"frontend house app",以便"frontend house app"自动创建整个节点树新加的房子。含义:填写了所需数据的 "house" 页面,每个房间的 "room" 页面等,以便 "frontend house app" 的内容管理员可以看到整个树工作区中新添加的房子,可以开始操作已有模板中的内容。除了自动创建这些页面,我还想预先设置更新和创建的权限,因为 "frontend house app" 的内容管理员一定不能 能够创建新的例如房间或更改房子的名称。
我没能成功,我将添加我已经完成的工作以显示我遇到的问题。
我从以下代码开始,在一个扩展 Sulu 自己的 WebsiteController 的控制器中:
$documentManager = $this->get('sulu_document_manager.document_manager');
$nodeManager = $this->get('sulu_document_manager.node_manager');
$parentHousesDocument = $documentManager->find('/cmf/immo/routes/nl/huizen', 'nl');
$newHouseDocument = $documentManager->create('page');
// The backendApi just gives a House object with data from the backend
// In this case we get an existing House with id 1
$house = $backendApi->getHouseWithId(1);
$newHouseDocument->setTitle($house->getName()); // For instance 'Smurfhouse'
$newHouseDocument->setLocale('nl'); // Nl is the only locale we have
$newHouseDocument->setParent($parentHouseDocument); // A default page where all the houses are listed
$newHouseDocument->setStructureType('house'); // Since we have a house.xml template
// I need to grab the structure to fill it with values from the House object
$structure = $newHouseDocument->getStructure();
$structure->bind([
'title' => $house->getName(),
'houseId' => $house->getId(),
]);
$newHouseDocument->setWorkflowStage(WorkflowStage::PUBLISHED); // You would expect this to automatically publish the document, but apparently it doesn't... I took it from a test I reverse-engineered in trying to create a page, I have no clue what it is supposed to change.
$nodeManager->createPath('/cmf/immo/routes/nl/huizen/' . $house->getId());
$documentManager->persist(
$newHouseDocument,
'nl',
[
'path' => '/cmf/immo/contents/huizen/' . Slugifier::slugify($house->getName()), // Assume for argument's sake that the Slugifier just slugifies the name...
'auto_create' => true, // Took this value from a test that creates pages, don't know whether it is necessary
'load_ghost_content' => false, // Idem
]
);
$documentManager->flush();
现在,当我触发控制器操作时,我首先得到异常
Property "url" in structure "house" is required but no value was given.
我试图通过手动将 属性 'url'
与值 '/huizen/' . $house->getId()
绑定到 $structure
来解决这个问题,在我绑定其他值的地方。但这并不能解决问题,显然 url 值在持久事件链中的某处被覆盖,我还没有找到 .
的位置
但是,出于测试目的,我可以手动覆盖 StructureSubscriber
中处理此特定持续事件映射的 url。如果我这样做,Sulu-app-database 中会创建一些东西 - 欢呼!
我的 phpcr_nodes
table 列出了两条额外的记录,一条用于引用 /cmf/immo/routes/nl/huizen/1
的 RouteDocument,另一条用于引用 /cmf/immo/contents/huizen/smurfhouse
的 PageDocument。两者都在 workspace_name
列中填充了值 default_live
。但是,只要除了 workspace_name
列中的值 default
之外没有与这两条记录完全重复的记录, 页面就不会出现在 Sulu 管理中CMS 环境。不用说,它们也 不会出现在 public 网站上。
此外,当我让 DocumentManager 在我的控制器操作中尝试 ->find
我新创建的文档时,我得到了 class UnknownDocument
的文档。因此,我不能让 DocumentManager 在其上运行 ->publish
;发生异常。如果我访问 Sulu 管理环境中的页面,它们将因此未发布;一旦我在那里发布它们,它们可以在控制器操作中被 DocumentManager 找到 - 即使我稍后取消发布它们。由于某种原因,它们不再是 UnknownDocument
。但是,即使可以找到它们,我也不能让 DocumentManager 进入 ->unpublish
或 ->publish
- 这对实际文档没有影响。
我希望会有一个 Sulu 食谱或另一篇文档,广泛描述如何动态创建完全发布的页面,从而无需通过实际 CMS 环境的 'manual labor',但是到目前为止我还没有找到...非常感谢所有帮助:)
PS:为了完整起见:我们在 PHP 7.1 的 Windows 服务器环境中 运行ning Sulu; dbase 是 PostgreSQL,Sulu 是发布标签 1.4.7 的本地分叉版本,因为我必须对 Sulu 处理上传文件的方式进行一些更改以使其在 Windows 环境中工作。
编辑:如果 none 已经存在,则制作新主页的部分解决方案(未明确使用 AdminKernel,但当然应该 运行 在 AdminKernel 处于活动状态的上下文中) :
public function getOrCreateHuisPagina(Huis $huis)
{
$parent = $this->documentManager->find('/cmf/immo/routes/nl/huizen', 'nl'); // This is indeed the route document for the "collector page" of all the houses, but this doesn't seem to give any problems (see below)
try {
$document = $this->documentManager->find('/cmf/immo/routes/nl/huizen/' . $huis->id(), 'nl'); // Here I'm checking whether the page already exists
} catch(DocumentNotFoundException $e) {
$document = $this->setupPublishedPage();
$document->setTitle($huis->naam());
$document->setStructureType('huis_detail');
$document->setResourceSegment('/huizen');
$document->setParent($parent);
$document->getStructure()->bind([
'title' => $huis->naam(), // Not sure if this is required seeing as I already set the title
'huis_id' => $huis->id(),
]);
$this->documentManager->persist(
$document,
'nl',
[
'parent_path' => '/cmf/immo/contents/huizen', // Explicit path to the content document of the parnt
]
);
}
$this->documentManager->publish($document, 'nl');
return $document;
}
首先我认为下面这行没有加载你想要它加载的内容:
$parentHousesDocument = $documentManager->find('/cmf/immo/routes/nl/huizen', 'nl');
它加载路由而不是页面文档,因此它应该如下所示:
$parentHousesDocument = $documentManager->find('/cmf/immo/contents/nl/huizen', 'nl');
关于 URL 的错误,您应该简单地使用文档的 setResourceSegment
方法,而不是覆盖 StructureSubscriber
,这正是您需要的:-)
而且 default_live
工作区是错误的,有没有可能是你在网站内核上 运行ning 这些命令?问题是 WebsiteKernel 默认具有 default_live
工作区,因此将内容写入此工作区。如果您 运行 使用 AdminKernel
命令,它应该位于 default
工作区,并且您应该能够使用 [=19= 将它复制到 default_live
工作区] DocumentManager 的方法。
希望对您有所帮助:-)
我有以下情况:
- 数据库存储有关房屋的信息(地址、房间数量、建造日期、最后售价等)
- 此数据库是通过无法直接集成到 Sulu 驱动的应用程序中的应用程序(我们称该应用程序为 "backend house app")操作的。我可以通过 API 访问存储的数据,它为我提供 JSON-House-objects 的表示形式。我还可以让该应用程序在创建、更新或删除房屋时启动对 Sulu 驱动的应用程序的某种调用。
- 带有 "house"、"room" 等模板的 Sulu 驱动的应用程序(我们称之为 "frontend house app")连接到不同服务器上的不同数据库。这个 Sulu 驱动的应用程序的网站环境显示带有房间页面的房屋页面,其中一些内容是通过与 "backend house app" 的连接预填充的。其他内容仅存在于 "frontend house app" 的数据库中,如用户评论、室内设计评价等,根据 Sulu 模板的配置方面。
我想要实现的是一种基于"backend house app"activity自动创建、更新和删除"frontend house app"页面的方法.
例如,当在"backend house app"中添加新房子时,我希望它通知"frontend house app",以便"frontend house app"自动创建整个节点树新加的房子。含义:填写了所需数据的 "house" 页面,每个房间的 "room" 页面等,以便 "frontend house app" 的内容管理员可以看到整个树工作区中新添加的房子,可以开始操作已有模板中的内容。除了自动创建这些页面,我还想预先设置更新和创建的权限,因为 "frontend house app" 的内容管理员一定不能 能够创建新的例如房间或更改房子的名称。
我没能成功,我将添加我已经完成的工作以显示我遇到的问题。
我从以下代码开始,在一个扩展 Sulu 自己的 WebsiteController 的控制器中:
$documentManager = $this->get('sulu_document_manager.document_manager');
$nodeManager = $this->get('sulu_document_manager.node_manager');
$parentHousesDocument = $documentManager->find('/cmf/immo/routes/nl/huizen', 'nl');
$newHouseDocument = $documentManager->create('page');
// The backendApi just gives a House object with data from the backend
// In this case we get an existing House with id 1
$house = $backendApi->getHouseWithId(1);
$newHouseDocument->setTitle($house->getName()); // For instance 'Smurfhouse'
$newHouseDocument->setLocale('nl'); // Nl is the only locale we have
$newHouseDocument->setParent($parentHouseDocument); // A default page where all the houses are listed
$newHouseDocument->setStructureType('house'); // Since we have a house.xml template
// I need to grab the structure to fill it with values from the House object
$structure = $newHouseDocument->getStructure();
$structure->bind([
'title' => $house->getName(),
'houseId' => $house->getId(),
]);
$newHouseDocument->setWorkflowStage(WorkflowStage::PUBLISHED); // You would expect this to automatically publish the document, but apparently it doesn't... I took it from a test I reverse-engineered in trying to create a page, I have no clue what it is supposed to change.
$nodeManager->createPath('/cmf/immo/routes/nl/huizen/' . $house->getId());
$documentManager->persist(
$newHouseDocument,
'nl',
[
'path' => '/cmf/immo/contents/huizen/' . Slugifier::slugify($house->getName()), // Assume for argument's sake that the Slugifier just slugifies the name...
'auto_create' => true, // Took this value from a test that creates pages, don't know whether it is necessary
'load_ghost_content' => false, // Idem
]
);
$documentManager->flush();
现在,当我触发控制器操作时,我首先得到异常
Property "url" in structure "house" is required but no value was given.
我试图通过手动将 属性 'url'
与值 '/huizen/' . $house->getId()
绑定到 $structure
来解决这个问题,在我绑定其他值的地方。但这并不能解决问题,显然 url 值在持久事件链中的某处被覆盖,我还没有找到 .
但是,出于测试目的,我可以手动覆盖 StructureSubscriber
中处理此特定持续事件映射的 url。如果我这样做,Sulu-app-database 中会创建一些东西 - 欢呼!
我的 phpcr_nodes
table 列出了两条额外的记录,一条用于引用 /cmf/immo/routes/nl/huizen/1
的 RouteDocument,另一条用于引用 /cmf/immo/contents/huizen/smurfhouse
的 PageDocument。两者都在 workspace_name
列中填充了值 default_live
。但是,只要除了 workspace_name
列中的值 default
之外没有与这两条记录完全重复的记录, 页面就不会出现在 Sulu 管理中CMS 环境。不用说,它们也 不会出现在 public 网站上。
此外,当我让 DocumentManager 在我的控制器操作中尝试 ->find
我新创建的文档时,我得到了 class UnknownDocument
的文档。因此,我不能让 DocumentManager 在其上运行 ->publish
;发生异常。如果我访问 Sulu 管理环境中的页面,它们将因此未发布;一旦我在那里发布它们,它们可以在控制器操作中被 DocumentManager 找到 - 即使我稍后取消发布它们。由于某种原因,它们不再是 UnknownDocument
。但是,即使可以找到它们,我也不能让 DocumentManager 进入 ->unpublish
或 ->publish
- 这对实际文档没有影响。
我希望会有一个 Sulu 食谱或另一篇文档,广泛描述如何动态创建完全发布的页面,从而无需通过实际 CMS 环境的 'manual labor',但是到目前为止我还没有找到...非常感谢所有帮助:)
PS:为了完整起见:我们在 PHP 7.1 的 Windows 服务器环境中 运行ning Sulu; dbase 是 PostgreSQL,Sulu 是发布标签 1.4.7 的本地分叉版本,因为我必须对 Sulu 处理上传文件的方式进行一些更改以使其在 Windows 环境中工作。
编辑:如果 none 已经存在,则制作新主页的部分解决方案(未明确使用 AdminKernel,但当然应该 运行 在 AdminKernel 处于活动状态的上下文中) :
public function getOrCreateHuisPagina(Huis $huis)
{
$parent = $this->documentManager->find('/cmf/immo/routes/nl/huizen', 'nl'); // This is indeed the route document for the "collector page" of all the houses, but this doesn't seem to give any problems (see below)
try {
$document = $this->documentManager->find('/cmf/immo/routes/nl/huizen/' . $huis->id(), 'nl'); // Here I'm checking whether the page already exists
} catch(DocumentNotFoundException $e) {
$document = $this->setupPublishedPage();
$document->setTitle($huis->naam());
$document->setStructureType('huis_detail');
$document->setResourceSegment('/huizen');
$document->setParent($parent);
$document->getStructure()->bind([
'title' => $huis->naam(), // Not sure if this is required seeing as I already set the title
'huis_id' => $huis->id(),
]);
$this->documentManager->persist(
$document,
'nl',
[
'parent_path' => '/cmf/immo/contents/huizen', // Explicit path to the content document of the parnt
]
);
}
$this->documentManager->publish($document, 'nl');
return $document;
}
首先我认为下面这行没有加载你想要它加载的内容:
$parentHousesDocument = $documentManager->find('/cmf/immo/routes/nl/huizen', 'nl');
它加载路由而不是页面文档,因此它应该如下所示:
$parentHousesDocument = $documentManager->find('/cmf/immo/contents/nl/huizen', 'nl');
关于 URL 的错误,您应该简单地使用文档的 setResourceSegment
方法,而不是覆盖 StructureSubscriber
,这正是您需要的:-)
而且 default_live
工作区是错误的,有没有可能是你在网站内核上 运行ning 这些命令?问题是 WebsiteKernel 默认具有 default_live
工作区,因此将内容写入此工作区。如果您 运行 使用 AdminKernel
命令,它应该位于 default
工作区,并且您应该能够使用 [=19= 将它复制到 default_live
工作区] DocumentManager 的方法。
希望对您有所帮助:-)