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

时间:2017-02-28 12:49:54

标签: sulu

我有以下情况:

  • 数据库存储有关房屋的信息(地址,房间数,日期,最后售价等)
  • 这个数据库正在通过一个应用程序进行操作(让我们称之为应用程序"后端应用程序")无法直接集成到Sulu驱动的应用程序中。我可以通过API访问存储的数据,该API为我提供了House对象的JSON表示。我还可以让应用程序在创建,更新或删除房屋时启动对Sulu驱动的应用程序的某种调用。
  • Sulu驱动的应用程序(让我们称之为"前端应用程序")带有" house"," room"等模板。,连接到不同服务器上的不同数据库。这个由Sulu驱动的应用程序的网站环境显示带有房间页面的房屋页面,其中一些内容通过与后端房屋应用程序的连接预先填充。其他内容仅存在于"前端房屋应用程序的数据库中,如用户评论,室内设计评估等,根据Sulu模板的配置方面。

我想要实现的目标是根据"后端内部应用&#34中的活动自动创建,更新和删除"前端内部应用" -pages的方法;

例如,当在"后端房屋应用程序"中添加新房子时,我希望它通知"前端房屋应用程序"所以"前端的房子应用"将自动为新添加的房屋创建整个节点树。含义:a" house" -page填写所需的数据," room" -pages for each rooms等,以便"前端的内容管理员应用"可以在工作区中看到新添加的房屋的整个树,并可以开始操作已有模板中的内容。除了自动创建这些页面之外,我还想预先设置更新和创建的权限,因为"前端内部应用程序的内容管理器"例如,不得能够创建新房间或更改房屋名称。

我无法让它发挥作用,我只是添加我已经完成的工作来展示我遇到的问题。

我开始使用以下代码,在一个控制器中扩展了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();

现在,当我触发控制器动作时,我首先得到异常

  

财产" url"在结构"房子"是必需的,但没有给出任何价值。

我尝试通过手动将属性'url'与值'/huizen/' . $house->getId()绑定到$structure来解决此问题,我绑定了其他值。但这并没有解决它,显然url值在persist事件链的某处被覆盖了,而我还没有找到的位置。

但是,出于测试目的,我可以手动覆盖处理此特定持久性事件映射的StructureSubscriber中的URL。如果我这样做,会在Sulu-app-database中创建一些东西 - 欢呼!

我的phpcr_nodes表列出了两个额外的记录,一个用于引用/cmf/immo/routes/nl/huizen/1的RouteDocument,另一个用于引用/cmf/immo/contents/huizen/smurfhouse的PageDocument。两者都在workspace_name列中填充了值default_live。但是,只要不存在与这两个记录完全重复的记录,除了default列中的值workspace_name这些页面将不会出现在Sulu管理CMS环境中。毋庸置疑,他们也不会出现在公共网站上

此外,当我让控制器操作中的DocumentManager尝试->find我新创建的文档时,我会得到类UnknownDocument的文档。因此,我不能让DocumentManager对其进行->publish;随之而来的是一个例外。如果我访问Sulu管理环境中的页面,则它们未被发布;一旦我在那里发布它们,它们可以通过DocumentManager在控制器动作中找到 - 即使我稍后取消发布它们。由于某种原因,它们不再是UnknownDocument。但是,即使可以找到它们,我也不能让DocumentManager转到->unpublish->publish - 这对实际文档没有任何影响。

我希望有一份苏禄食谱 - 食谱或其他文件广泛描述如何动态创建完整发布的页面,因此无需通过“手工劳动”#39;实际的CMS环境,但到目前为止我还没有找到一个...所有的帮助非常感谢:)

PS:为了完成目的:我们在PHP 7.1的Windows服务器环境中运行Sulu; dbase是PostgreSQL,Sulu是发布标签1.4.7的本地分叉版本,因为我必须对Sulu处理上传文件的方式进行一些更改,以使其在Windows环境中工作。

编辑:如果不存在新房子页面,则制作新房屋页面的部分解决方案(未明确使用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;
}

1 个答案:

答案 0 :(得分:0)

首先,我认为以下行不会加载您要加载的内容:

$parentHousesDocument = $documentManager->find('/cmf/immo/routes/nl/huizen', 'nl');

它加载路径而不是页面文档,因此它应如下所示:

$parentHousesDocument = $documentManager->find('/cmf/immo/contents/nl/huizen', 'nl');

关于您使用网址的错误,而不是覆盖StructureSubscriber,您应该简单地使用文档的setResourceSegment方法,这正是您所需要的: - )

default_live工作空间错误,您是否有可能在网站内核上运行这些命令?问题是WebsiteKernel默认使用default_live工作空间,因此将内容写入此工作空间。如果您运行带有AdminKernel的命令,它应该落在default工作区中,您应该能够使用default_live方法将其复制到publish工作区中DocumentManager。

我希望有帮助: - )