Skip to content

Commit

Permalink
Fix EZP-29339: ezxmltext -> ricktext conversion : links with object_r…
Browse files Browse the repository at this point in the history
…emote_id="..." not suppor (ezsystems#51)

* EZP-29339: ezxmltext -> ricktext conversion : links with object_remote_id="..." not supported

* Fixed regression in RichText::checkEmptyEmbedTags()

* Added support for links with node_remote_id="..." in conversion tool
  • Loading branch information
vidarl committed Jun 28, 2018
1 parent 6cac253 commit c925216
Show file tree
Hide file tree
Showing 16 changed files with 184 additions and 15 deletions.
69 changes: 59 additions & 10 deletions lib/FieldType/XmlText/Converter/RichText.php
Expand Up @@ -39,16 +39,14 @@ class RichText implements Converter
private $apiRepository;

/**
* @var []
* @var Psr\Log\LoggerInterface
*/
private $styleSheets;
private $logger;

/**
* Holds the id of the current contentField being converted.
*
* @var null|int
* @var []
*/
private $currentContentFieldId;
private $styleSheets;

/**
* RichText constructor.
Expand Down Expand Up @@ -337,31 +335,82 @@ public function tagEmbeddedImages(DOMDocument $richtextDocument, $contentFieldId
/**
* Check if $inputDocument has any embed|embed-inline tags without node_id or object_id.
* @param DOMDocument $inputDocument
* @param $contentFieldId
*/
protected function checkEmptyEmbedTags(DOMDocument $inputDocument)
protected function checkEmptyEmbedTags(DOMDocument $inputDocument, $contentFieldId)
{
$xpath = new DOMXPath($inputDocument);
$nodes = $xpath->query('//embed[not(@node_id|@object_id)] | //embed-inline[not(@node_id|@object_id)]');
if ($nodes->length > 0) {
$this->logger->warning('Warning: ezxmltext for contentobject_attribute.id=' . $this->currentContentFieldId . 'contains embed or embed-inline tag(s) without node_id or object_id');
$this->logger->warning('Warning: ezxmltext for contentobject_attribute.id=' . $contentFieldId . 'contains embed or embed-inline tag(s) without node_id or object_id');
}
}

/**
* Before calling this function, make sure you are logged in as admin, or at least have access to all the objects
* being linked to in the $document.
* @param DOMDocument $document
* @param $contentFieldId
*/
protected function checkLinkTags(DOMDocument $document, $contentFieldId)
{
$xpath = new DOMXPath($document);

// Get all link elements except those handled directly by xslt
$xpathExpression = '//link[not(@url_id) and not(@node_id) and not(@object_id) and not(@anchor_name) and not(@href)]';

$links = $xpath->query($xpathExpression);

foreach ($links as $link) {
if ($link->hasAttribute('object_remote_id')) {
$remote_id = $link->getAttribute('object_remote_id');
try {
$contentInfo = $this->apiRepository->getContentService()->loadContentInfoByRemoteId($remote_id);
$link->setAttribute('object_id', $contentInfo->id);
} catch (NotFoundException $e) {
// The link has to point to somewhere in order to be valid... Pointing to current page
$link->setAttribute('href', '#');
$this->logger->warning("Unable to find content object with remote_id=$remote_id (so rewriting to href=\"#\"), when converting link where contentobject_attribute.id=$contentFieldId.");
}
continue;
}

if ($link->hasAttribute('node_remote_id')) {
$remote_id = $link->getAttribute('node_remote_id');
try {
$location = $this->apiRepository->getLocationService()->loadLocationByRemoteId($remote_id);
$link->setAttribute('node_id', $location->id);
} catch (NotFoundException $e) {
// The link has to point to somewhere in order to be valid... Pointing to current page
$link->setAttribute('href', '#');
$this->logger->warning("Unable to find node with remote_id=$remote_id (so rewriting to href=\"#\"), when converting link where contentobject_attribute.id=$contentFieldId.");
}
continue;
}
// The link has to point to somewhere in order to be valid... Pointing to current page
$link->setAttribute('href', '#');
$this->logger->warning("Unknown linktype detected when converting link where contentobject_attribute.id=$contentFieldId.");
}
}

/**
* Before calling this function, make sure you are logged in as admin, or at least have access to all the objects
* being embedded in the $inputDocument.
* being embedded and linked to in the $inputDocument.
*
* @param DOMDocument $inputDocument
* @param bool $checkDuplicateIds
* @param bool $checkIdValues
* @param null|int $contentFieldId
* @return string
* @throws \Exception
*/
public function convert(DOMDocument $inputDocument, $checkDuplicateIds = false, $checkIdValues = false, $contentFieldId = null)
{
$this->removeComments($inputDocument);
$this->checkEmptyEmbedTags($inputDocument, $contentFieldId);
$this->checkLinkTags($inputDocument, $contentFieldId);

$this->checkEmptyEmbedTags($inputDocument);
try {
$convertedDocument = $this->getConverter()->convert($inputDocument);
} catch (\Exception $e) {
Expand Down
Expand Up @@ -270,11 +270,6 @@
<xsl:value-of select="concat( '', @href )"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
Unhandled link type
</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:attribute name="xlink:show">
<xsl:choose>
Expand Down
42 changes: 42 additions & 0 deletions tests/lib/FieldType/Converter/RichTextTest.php
Expand Up @@ -18,6 +18,7 @@
use eZ\Publish\API\Repository\Values\Content\ContentInfo;
use eZ\Publish\API\Repository\Values\Content\Location;
use Psr\Log\NullLogger;
use eZ\Publish\Core\Base\Exceptions\NotFoundException;

class RichTextTest extends TestCase
{
Expand Down Expand Up @@ -97,6 +98,42 @@ protected function normalizeRewrittenIds(DOMDocument $xmlDoc)
}
}

public function callbackLoadContentInfoByRemoteId($arg)
{
// We have to use callback because returnValueMap() is useless if one argument value is supposed
// to trow exception.
if ($arg === 'my_invalid_remote_id') {
throw new NotFoundException('foobar_message', 'foobar_identifier');
}
if ($arg === 'my_remote_id') {
$contentInfoRemoteIdStub = $this->createMock(ContentInfo::class);
$contentInfoRemoteIdStub
->method('__get')
->with($this->equalTo('id'))
->willReturn(42);

return $contentInfoRemoteIdStub;
}
}

public function callbackLoadLocationByRemoteId($arg)
{
// We have to use callback because returnValueMap() is useless if one argument value is supposed
// to trow exception.
if ($arg === 'my_invalid_remote_id') {
throw new NotFoundException('foobar_message', 'foobar_identifier');
}
if ($arg === 'my_remote_id') {
$locationRemoteIdStub = $this->createMock(Location::class);
$locationRemoteIdStub
->method('__get')
->with($this->equalTo('id'))
->willReturn(4242);

return $locationRemoteIdStub;
}
}

private function createApiRepositoryStub()
{
$apiRepositoryStub = $this->createMock(Repository::class);
Expand All @@ -118,12 +155,17 @@ private function createApiRepositoryStub()
$contentServiceStub->method('loadContentInfo')
->will($this->returnValueMap($map));

$contentServiceStub->method('loadContentInfoByRemoteId')
->will($this->returnCallBack([$this, 'callbackLoadContentInfoByRemoteId']));

// image content type has id=27, file content type has id=27
$contentInfoImageStub->method('__get')->willReturn(27);
$contentInfoFileStub->method('__get')->willReturn(25);

$locationServiceStub->method('loadLocation')->willReturn($locationStub);
$locationStub->method('getContentInfo')->willReturn($contentInfoImageStub);
$locationServiceStub->method('loadLocationByRemoteId')
->will($this->returnCallBack([$this, 'callbackLoadLocationByRemoteId']));

return $apiRepositoryStub;
}
Expand Down
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<section xmlns:image="http://ez.no/namespaces/ezpublish3/image/" xmlns:xhtml="http://ez.no/namespaces/ezpublish3/xhtml/" xmlns:custom="http://ez.no/namespaces/ezpublish3/custom/">
<paragraph>foobartext
<link object_remote_id="my_remote_id">link</link>
</paragraph>
</section>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<section xmlns:image="http://ez.no/namespaces/ezpublish3/image/" xmlns:xhtml="http://ez.no/namespaces/ezpublish3/xhtml/" xmlns:custom="http://ez.no/namespaces/ezpublish3/custom/">
<paragraph>foobartext
<link object_remote_id="my_invalid_remote_id">link</link>
</paragraph>
</section>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<section xmlns:image="http://ez.no/namespaces/ezpublish3/image/" xmlns:xhtml="http://ez.no/namespaces/ezpublish3/xhtml/" xmlns:custom="http://ez.no/namespaces/ezpublish3/custom/">
<paragraph>foobartext
<link not_supported="foobar">link</link>
</paragraph>
</section>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<section xmlns:image="http://ez.no/namespaces/ezpublish3/image/" xmlns:xhtml="http://ez.no/namespaces/ezpublish3/xhtml/" xmlns:custom="http://ez.no/namespaces/ezpublish3/custom/">
<paragraph>foobartext
<link node_remote_id="my_remote_id">link</link>
</paragraph>
</section>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<section xmlns:image="http://ez.no/namespaces/ezpublish3/image/" xmlns:xhtml="http://ez.no/namespaces/ezpublish3/xhtml/" xmlns:custom="http://ez.no/namespaces/ezpublish3/custom/">
<paragraph>foobartext
<link node_remote_id="my_invalid_remote_id">link</link>
</paragraph>
</section>
@@ -0,0 +1 @@
warning:Unable to find content object with remote_id=my_invalid_remote_id (so rewriting to href="#"), when converting link where contentobject_attribute.id=.
@@ -0,0 +1 @@
warning:Unknown linktype detected when converting link where contentobject_attribute.id=.
@@ -0,0 +1 @@
warning:Unable to find node with remote_id=my_invalid_remote_id (so rewriting to href="#"), when converting link where contentobject_attribute.id=.
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml"
xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
<para>foobartext
<link xlink:href="ezcontent://42" xlink:show="none">link</link>
</para>
</section>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml"
xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
<para>foobartext
<link xlink:href="#" xlink:show="none">link</link>
</para>
</section>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml"
xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
<para>foobartext
<link xlink:href="#" xlink:show="none">link</link>
</para>
</section>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml"
xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
<para>foobartext
<link xlink:href="ezlocation://4242" xlink:show="none">link</link>
</para>
</section>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<section
xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ezxhtml="http://ez.no/xmlns/ezpublish/docbook/xhtml"
xmlns:ezcustom="http://ez.no/xmlns/ezpublish/docbook/custom" version="5.0-variant ezpublish-1.0">
<para>foobartext
<link xlink:href="#" xlink:show="none">link</link>
</para>
</section>

0 comments on commit c925216

Please sign in to comment.