Как я могу динамически создавать и обновлять страницы в Sulu CMS?

У меня следующая ситуация:

  • В базе данных хранится информация о домах (адрес, количество комнат, дата постройки, цена последней продажи и т.д.)
  • Управление этой базой данных осуществляется через приложение (назовем это приложение «внутренним приложением»), которое нельзя напрямую интегрировать в приложение, управляемое Sulu. Я могу получить доступ к сохраненным данным через API, который дает мне JSON-представление House-объектов. Я также могу заставить приложение запускать какой-то вызов к приложению, управляемому Sulu, когда дом создается, обновляется или удаляется.
  • Приложение, управляемое Sulu (назовем его «домашнее приложение внешнего интерфейса») с шаблонами для «дома», «комнаты» и т. д., подключено к другой базе данных на другом сервере. Среда веб-сайта этого приложения, управляемого Sulu, показывает домашние страницы со страницами комнат, где некоторый контент предварительно заполняется через подключение к «внутреннему домашнему приложению». Другой контент существует только в базе данных «приложения внешнего интерфейса», например, комментарии пользователей, оценки дизайна интерьера и т. Д., В соответствии с настроенными аспектами шаблонов Sulu.

Чего я хочу достичь, так это способа автоматизировать создание, обновление и удаление страниц "собственного внешнего интерфейса" на основе действий в "собственном внутреннем приложении".

Например, когда новый дом добавляется в «внутреннее приложение дома», я хочу, чтобы он уведомлял «приложение внешнего интерфейса», чтобы «приложение внешнего интерфейса» автоматически создавало все дерево узлов для вновь добавленного дома. Значение: "дом"-страница с заполненными необходимыми данными, "комната"-страницы для каждой комнаты и т. д., чтобы контент-менеджер "интерфейсного приложения дома" мог видеть все дерево вновь добавленного дома в рабочей области и может начать манипулировать содержимым в уже доступных шаблонах. В дополнение к автоматическому созданию этих страниц, я также хочу предварительно установить права на обновление и создание, так как контент-менеджер «приложения для внешнего интерфейса» не должен иметь возможность создавать новые комнаты или изменять например, название дома.

Мне не удалось заставить его работать, я просто добавлю то, что уже сделал, чтобы показать, где я застрял.

Я начал со следующего кода в контроллере, который расширяет собственный WebsiteController Sulu:

$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 перезаписывается где-то в цепочке событий сохранения, и я еще не нашел, где.

Однако я могу, только в целях тестирования, вручную переопределить URL-адрес в StructureSubscriber, который обрабатывает сопоставление для этого конкретного события сохранения. Если я это сделаю, что-то будет создано в базе данных Sulu-app-database — ура!

В моей таблице phpcr_nodes есть две дополнительные записи: одна для RouteDocument, относящаяся к /cmf/immo/routes/nl/huizen/1, и одна для PageDocument, относящаяся к /cmf/immo/contents/huizen/smurfhouse. У обоих столбец workspace_name заполнен значением default_live. Однако если нет записей, полностью дублирующих эти две записи, за исключением значений default в столбце workspace_name, страницы не будут отображаться в среде CMS администрирования Sulu. Излишне говорить, что они также не будут отображаться на общедоступном веб-сайте.

Кроме того, когда я позволяю DocumentManager в действии моего контроллера попытаться ->find создать мой вновь созданный документ, я получаю документ класса UnknownDocument. Следовательно, я не могу заставить DocumentManager работать ->publish на нем; возникает Исключение. Если я посещаю страницы в административной среде Sulu, они, следовательно, не публикуются; как только я опубликую их там, Менеджер документов сможет их найти в действии контроллера, даже если я позже отменю их публикацию. По какой-то причине им больше не UnknownDocument. Однако, даже если их можно найти, я не могу заставить DocumentManager идти ->unpublish или ->publish - это просто НЕ влияет на фактические документы.

Я надеялся, что появится кулинарная книга-рецепт Sulu или другая документация, подробно описывающая, как динамически создавать полностью опубликованные страницы, не прибегая к «ручному труду» фактической среды CMS, но до сих пор я не нашел один ... Вся помощь очень ценится :)

PS: Для полноты: мы запускаем Sulu в среде сервера Windows на PHP 7.1; 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;
}

person Tom De Roo    schedule 28.02.2017    source источник


Ответы (1)


Прежде всего, я думаю, что следующая строка не загружает то, что вы хотите загрузить:

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

Он загружает маршрут вместо документа страницы, поэтому он должен выглядеть следующим образом:

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

Что касается вашей ошибки с URL-адресом, вместо переопределения StructureSubscriber вы должны просто использовать метод setResourceSegment документа, который делает именно то, что вам нужно :-)

И рабочая область default_live неверна, возможно ли, что вы запускаете эти команды в ядре веб-сайта? Дело в том, что WebsiteKernel по умолчанию имеет рабочую область default_live, поэтому и записывает контент в эту рабочую область. Если вы запустите команду с AdminKernel, она должна попасть в рабочую область default, и вы сможете скопировать ее в рабочую область default_live с помощью метода publish DocumentManager.

Надеюсь, это поможет :-)

person Daniel Rotter    schedule 20.03.2017
comment
Да, default_live происходит от запуска этого в WebsiteController. Я исправил это случайно, преобразовав его в консольную команду, которая запускается в AdminKernel. Но учитывая, что теперь я знаю, что AdminKernel — это то, что мне нужно, я могу просто создать новый фронтконтроллер специально для всей части update-a-new-house и заставить его запускать AdminKernel — ура :) Мне удалось переписать процесс во что-то, что больше не требует URL-адреса и работает с документом маршрута (я добавлю его к моему вопросу), но я попробую это напрямую с документом страницы в любом случае - спасибо! - person Tom De Roo; 06.04.2017