Skip to content

Commit

Permalink
Add support for exporting/importing page aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
mlocati committed Nov 9, 2024
1 parent a9a657d commit a3795c2
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public function import(SimpleXMLElement $sx)
if (!isset($sx->pages)) {
return;
}
$childElements = [];
foreach ($sx->pages->children() as $childElement) {
$childElements[] = $childElement;
$elements = [];
foreach ($sx->pages->children() as $element) {
$elements[] = $element;
}
if ($childElements === []) {
if ($elements === []) {
return;
}
if (!$this->home || $this->home->isError()) {
Expand All @@ -57,23 +57,48 @@ public function import(SimpleXMLElement $sx)
}
}
$this->defaultSiteTree = $this->home->getSiteTreeObject();
$childElements = $this->sortElementsByPath($childElements);
foreach ($childElements as $childElement) {
switch ($childElement->getName()) {
case 'page':
$localeInfo = $this->extractLocale($childElement);
$page = $this->getOrCreatePage($childElement, $localeInfo);
$this->importAdditionalPagePaths($childElement, $page);
break;
case 'external-link':
$this->importExternalLink($childElement);
break;
$elements = $this->sortElementsByPath($elements);
while ($elements !== []) {
$delayed = [];
$errorMessages = [];
foreach ($elements as $element) {
$importResult = null;
switch ($element->getName()) {
case 'page':
$localeInfo = $this->extractLocale($element);
$importResult = $this->getOrCreatePage($element, $localeInfo);
if (is_object($importResult)) {
$this->importAdditionalPagePaths($element, $importResult);
}
break;
case 'external-link':
$importResult = $this->importExternalLink($element);
break;
case 'alias':
$importResult = $this->importAlias($element);
break;
}
if (is_string($importResult)) {
$delayed[] = $element;
$errorMessages[] = $importResult;
}
}
if (count($delayed) == count($elements)) {
throw new UserMessageException(implode("\n", $errorMessages));
}
$elements = $delayed;
$this->clearPageCache();
}
}

private function clearPageCache()
{
$cache = app('cache/request');
$cache->flush();
}

/**
* @return \Concrete\Core\Page\Page
* @return \Concrete\Core\Page\Page|string returns a string describing why we should import the page later on, or the created page otherwise
*/
private function getOrCreatePage(SimpleXMLElement $pageElement, array $localeInfo = null)
{
Expand All @@ -92,13 +117,10 @@ private function getOrCreatePage(SimpleXMLElement $pageElement, array $localeInf
$page = $this->home;
} else {
$pagePath = '/' . implode('/', $pathSlugs);
$page = Page::getByPath($pagePath, 'RECENT', $this->defaultSiteTree);
if (!$page || $page->isError() && $this->defaultSiteTree === null) {
$page = Page::getByPath($pagePath, 'RECENT');
}
$page = $this->getPageByPath($pagePath, 'RECENT');
}

if ($page && !$page->isError()) {
if ($page !== null) {
if ($localeInfo !== null) {
$this->updateExistingLocale($page, $localeInfo);
}
Expand All @@ -120,12 +142,9 @@ private function getOrCreatePage(SimpleXMLElement $pageElement, array $localeInf
$parent = $this->home;
} else {
$parentPagePath = '/' . implode('/', $slugs);
$parent = Page::getByPath($parentPagePath, 'RECENT', $this->defaultSiteTree);
if ((!$parent || $parent->isError()) && $this->defaultSiteTree !== null) {
$parent = Page::getByPath($parentPagePath, 'RECENT');
}
if (!$parent || $parent->isError()) {
throw new UserMessageException(t('Missing the page with path %s', $parentPagePath));
$parent = $this->getPageByPath($parentPagePath);
if ($parent === null) {
return (t('Missing the page with path %s', $parentPagePath));
}
}
if ($localeInfo === null || $this->localeAlreadyExists($localeInfo)) {
Expand Down Expand Up @@ -229,6 +248,9 @@ private function importAdditionalPagePaths(SimpleXMLElement $pageElement, Page $
$em->flush();
}

/**
* @return \Concrete\Core\Page\Page|null returns NULL if the parent page doesn't exist yet
*/
private function importExternalLink(SimpleXMLElement $externalLinkElement)
{
$slugs = preg_split('{/}', (string) $externalLinkElement['path'], -1, PREG_SPLIT_NO_EMPTY);
Expand All @@ -237,12 +259,9 @@ private function importExternalLink(SimpleXMLElement $externalLinkElement)
throw new UserMessageException(t('Missing the path of the external link'));
}
$parentPagePath = '/' . implode('/', $slugs);
$parent = Page::getByPath($parentPagePath, 'RECENT', $this->defaultSiteTree);
if ((!$parent || $parent->isError()) && $this->defaultSiteTree !== null) {
$parent = Page::getByPath($parentPagePath, 'RECENT');
}
if (!$parent || $parent->isError()) {
throw new UserMessageException(t('Missing the page with path %s', $parentPagePath));
$parent = $this->getPageByPath($parentPagePath);
if ($parent === null) {
return t('Missing the page with path %s', $parentPagePath);
}
$cID = $parent->addCollectionAliasExternal(
(string) $externalLinkElement['name'],
Expand All @@ -255,5 +274,61 @@ private function importExternalLink(SimpleXMLElement $externalLinkElement)
'cHandle' => $cHandle,
]);
}

return $page;
}

/**
* @return \Concrete\Core\Page\Page|null returns NULL if the parent page and/or the original page don't exist yet
*/
private function importAlias(SimpleXMLElement $aliasElement)
{
$slugs = preg_split('{/}', (string) $aliasElement['path'], -1, PREG_SPLIT_NO_EMPTY);
$cHandle = array_pop($slugs);
if ($cHandle === null) {
throw new UserMessageException(t('Missing the path of the external link'));
}
$parentPagePath = '/' . implode('/', $slugs);
$parentPage = $this->getPageByPath($parentPagePath);
if ($parentPage === null) {
return t('Missing the page with path %s', $parentPagePath);
}
$originalPagePath = '/' . trim((string) $aliasElement['original-path'], '/');
$originalPage = $this->getPageByPath($originalPagePath);
if ($originalPage === null) {
return t('Missing the page with path %s', $originalPagePath);
}
$userName = (string) $aliasElement['user'];
$userInfo = $userName === '' ? null : app(UserInfoRepository::class)->getByName($userName);
$alias = $originalPage->createAlias($parentPage, [
'name' => (string) $aliasElement['name'],
'handle' => $cHandle,
'uID' => $userInfo === null ? USER_SUPER_ID : $userInfo->getUserID(),
]);

return $alias;
}

/**
* @return \Concrete\Core\Page\Page|null
*/
private function getPageByPath($path)
{
$path = '/' . trim($path, '/');
if ($path === '/') {
return $this->home;
}
$page = Page::getByPath($path, 'RECENT', $this->defaultSiteTree);
if ($page && !$page->isError()) {
return $page;
}
if ($this->defaultSiteTree !== null) {
$page = Page::getByPath($path, 'RECENT');
if ($page && !$page->isError()) {
return $page;
}
}

return null;
}
}
127 changes: 77 additions & 50 deletions concrete/src/Page/Exporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,33 @@

class Exporter implements ItemInterface
{
const TYPE_PAGE = 'page';
const TYPE_ALIAS = 'alias';
const TYPE_EXTERNALLINK = 'external-link';

/**
* @param \Concrete\Core\Page\Page $mixed
*/
public function export($mixed, SimpleXMLElement $element)
{
$isExternalLink = $mixed->isExternalLink();
$p = $element->addChild($isExternalLink ? 'external-link' : 'page');
if ($mixed->isExternalLink()) {
$type = self::TYPE_EXTERNALLINK;
} elseif ($mixed->isAliasPage()) {
$type = self::TYPE_ALIAS;
$aliasedPage = Page::getByID($mixed->getCollectionPointerID());
} else {
$type = self::TYPE_PAGE;
}
$p = $element->addChild($type);
$p->addAttribute('name', $mixed->getCollectionName());
$p->addAttribute('path', $isExternalLink ? $mixed->generatePagePath() : $mixed->getCollectionPath());
switch ($type) {
case self::TYPE_EXTERNALLINK:
$p->addAttribute('path', $mixed->generatePagePath());
break;
default:
$p->addAttribute('path', $mixed->getCollectionPath());
break;
}
$uiRepository = app(UserInfoRepository::class);
$ui = null;
$uID = $mixed->getCollectionUserID();
Expand All @@ -30,56 +48,65 @@ public function export($mixed, SimpleXMLElement $element)
if ($ui === null) {
$ui = $uiRepository->getByID(USER_SUPER_ID);
}
$p->addAttribute('user', $ui->getUserName());
$p->addAttribute('public-date', $mixed->getCollectionDatePublic());
if ($isExternalLink) {
$p->addAttribute('destination', $mixed->getCollectionPointerExternalLink());
$p->addAttribute('new-window', $mixed->openCollectionPointerExternalLinkInNewWindow() ? 'true' : 'false');
} else {
$p->addAttribute('filename', $mixed->getCollectionFilename());
$p->addAttribute('pagetype', $mixed->getPageTypeHandle());
$locale = $this->getLocaleForHome($mixed);
if ($locale !== null) {
$this->exportLocaleRoot($p, $locale);
}
$this->exportAdditionalPagePaths($p, $mixed);
$hrefLangMap = $this->getHrefLangMap($mixed);
if ($hrefLangMap !== []) {
$this->exportHrefLangMap($p, $hrefLangMap);
}
$templateID = $mixed->getPageTemplateID();
if ($templateID) {
$template = app(EntityManagerInterface::class)->find(\Concrete\Core\Entity\Page\Template::class, $templateID);
if ($template) {
$p->addAttribute('template', $template->getPageTemplateHandle());
switch ($type) {
case self::TYPE_EXTERNALLINK:
$p->addAttribute('destination', $mixed->getCollectionPointerExternalLink());
$p->addAttribute('new-window', $mixed->openCollectionPointerExternalLinkInNewWindow() ? 'true' : 'false');
$p->addAttribute('user', $ui->getUserName());
$p->addAttribute('public-date', $mixed->getCollectionDatePublic());
break;
case self::TYPE_ALIAS:
$p->addAttribute('original-path', $aliasedPage->getCollectionPath());
$p->addAttribute('user', $ui->getUserName());
break;
case self::TYPE_PAGE:
$p->addAttribute('user', $ui->getUserName());
$p->addAttribute('public-date', $mixed->getCollectionDatePublic());
$p->addAttribute('filename', $mixed->getCollectionFilename());
$p->addAttribute('pagetype', $mixed->getPageTypeHandle());
$locale = $this->getLocaleForHome($mixed);
if ($locale !== null) {
$this->exportLocaleRoot($p, $locale);
}
}
$p->addAttribute('description', $mixed->getCollectionDescription());
if ($mixed->getCollectionParentID() == 0) {
if ($mixed->getSiteTreeID() == 0) {
$p->addAttribute('global', 'true');
} else {
$p->addAttribute('root', 'true');
$this->exportAdditionalPagePaths($p, $mixed);
$hrefLangMap = $this->getHrefLangMap($mixed);
if ($hrefLangMap !== []) {
$this->exportHrefLangMap($p, $hrefLangMap);
}
}
$attribs = $mixed->getSetCollectionAttributes();
if ($attribs !== []) {
$attributes = $p->addChild('attributes');
foreach ($attribs as $ak) {
$av = $mixed->getAttributeValueObject($ak);
$cnt = $ak->getController();
$cnt->setAttributeValue($av);
$akx = $attributes->addChild('attributekey');
$akx->addAttribute('handle', $ak->getAttributeKeyHandle());
$cnt->exportValue($akx);
$templateID = $mixed->getPageTemplateID();
if ($templateID) {
$template = app(EntityManagerInterface::class)->find(\Concrete\Core\Entity\Page\Template::class, $templateID);
if ($template) {
$p->addAttribute('template', $template->getPageTemplateHandle());
}
}
}

$r = app(Connection::class)->executeQuery('select arHandle from Areas where cID = ? and arIsGlobal = 0 and arParentID = 0', [$mixed->getCollectionID()]);
while ($row = $r->FetchRow()) {
$ax = Area::get($mixed, $row['arHandle']);
$ax->export($p, $mixed);
}
$p->addAttribute('description', $mixed->getCollectionDescription());
if ($mixed->getCollectionParentID() == 0) {
if ($mixed->getSiteTreeID() == 0) {
$p->addAttribute('global', 'true');
} else {
$p->addAttribute('root', 'true');
}
}
$attribs = $mixed->getSetCollectionAttributes();
if ($attribs !== []) {
$attributes = $p->addChild('attributes');
foreach ($attribs as $ak) {
$av = $mixed->getAttributeValueObject($ak);
$cnt = $ak->getController();
$cnt->setAttributeValue($av);
$akx = $attributes->addChild('attributekey');
$akx->addAttribute('handle', $ak->getAttributeKeyHandle());
$cnt->exportValue($akx);
}
}

$r = app(Connection::class)->executeQuery('select arHandle from Areas where cID = ? and arIsGlobal = 0 and arParentID = 0', [$mixed->getCollectionID()]);
while ($row = $r->FetchRow()) {
$ax = Area::get($mixed, $row['arHandle']);
$ax->export($p, $mixed);
}
break;
}
$p->addAttribute('package', $mixed->getPackageHandle());
}
Expand Down

0 comments on commit a3795c2

Please sign in to comment.