如何在 Sulu CMS 中动态创建和更新页面?

How can I create and update pages dynamically in Sulu CMS?

我有以下情况:

我想要实现的是一种基于"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 的方法。

希望对您有所帮助:-)