Skip to content

Commit

Permalink
EZP-28174: Validation of ezobject:// and eznode:// links in the xml t…
Browse files Browse the repository at this point in the history
…ext field type (#28)
  • Loading branch information
adamwojs authored and andrerom committed Dec 7, 2017
1 parent d7d3644 commit 86f8cc0
Show file tree
Hide file tree
Showing 5 changed files with 408 additions and 0 deletions.
8 changes: 8 additions & 0 deletions bundle/Resources/config/fieldtype_services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ parameters:
ezpublish.fieldType.ezxmltext.converter.ezLinkToHtml5.class: eZ\Publish\Core\FieldType\XmlText\Converter\EzLinkToHtml5
ezpublish.fieldType.ezxmltext.converter.expanding.class: eZ\Publish\Core\FieldType\XmlText\Converter\Expanding
ezpublish.fieldType.ezxmltext.converter.embedLinking.class: eZ\Publish\Core\FieldType\XmlText\Converter\EmbedLinking
ezpublish.fieldType.ezxmltext.validator.internal_link.class: eZ\Publish\Core\FieldType\XmlText\InternalLinkValidator

services:
ezpublish.fieldType.ezxmltext.converter.html5:
Expand Down Expand Up @@ -44,3 +45,10 @@ services:
- "@?logger"
tags:
- { name: ezpublish.ezxml.converter, priority: 8 }

ezpublish.fieldType.ezxmltext.validator.internal_link:
class: '%ezpublish.fieldType.ezxmltext.validator.internal_link.class%'
arguments:
- '@ezpublish.spi.persistence.cache.contentHandler'
- '@ezpublish.spi.persistence.cache.locationHandler'

128 changes: 128 additions & 0 deletions lib/FieldType/XmlText/InternalLinkValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php
/**
* File containing the eZ\Publish\Core\FieldType\XmlText\InternalLinkValidator class.
*
* @copyright Copyright (C) eZ Systems AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
namespace eZ\Publish\Core\FieldType\XmlText;

use DOMDocument;
use DOMXPath;
use eZ\Publish\SPI\Persistence\Content\Handler as ContentHandler;
use eZ\Publish\SPI\Persistence\Content\Location\Handler as LocationHandler;
use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentException;

/**
* Validator for XmlText internal format links.
*/
class InternalLinkValidator
{
/**
* @var \eZ\Publish\SPI\Persistence\Content\Handler
*/
private $contentHandler;

/**
* @var \eZ\Publish\SPI\Persistence\Content\Location\Handler;
*/
private $locationHandler;

/**
* InternalLinkValidator constructor.
* @param \eZ\Publish\SPI\Persistence\Content\Handler $contentHandler
* @param \eZ\Publish\SPI\Persistence\Content\Location\Handler $locationHandler
*/
public function __construct(ContentHandler $contentHandler, LocationHandler $locationHandler)
{
$this->contentHandler = $contentHandler;
$this->locationHandler = $locationHandler;
}

/**
* Extracts and validate internal links.
*
* @param \DOMDocument $xml
* @return array
*/
public function validate(DOMDocument $xml)
{
$errors = [];

$xpath = new DOMXPath($xml);
foreach ($xpath->query('//link') as $link) {
if ($link->hasAttribute('object_id')) {
$objectId = $link->getAttribute('object_id');
if ($objectId && !$this->validateEzObject($objectId)) {
$errors[] = $this->getInvalidLinkError('ezobject', $objectId, $link->getAttribute('anchor_name'));
}
} elseif ($link->hasAttribute('node_id')) {
$nodeId = $link->getAttribute('node_id');
if ($nodeId && !$this->validateEzNode($nodeId)) {
$errors[] = $this->getInvalidLinkError('eznode', $nodeId, $link->getAttribute('anchor_name'));
}
}
}

return $errors;
}

/**
* Validates link in "ezobject://" format.
*
* @param int $objectId
* @return bool
*/
protected function validateEzObject($objectId)
{
try {
$this->contentHandler->loadContentInfo($objectId);
} catch (NotFoundException $e) {
return false;
}

return true;
}

/**
* Validates link in "eznode://" format.
*
* @param mixed $nodeId
* @return bool
*/
protected function validateEzNode($nodeId)
{
try {
$this->locationHandler->load($nodeId);
} catch (NotFoundException $e) {
return false;
}

return true;
}

/**
* Builds error message for invalid url.
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If given $scheme is not supported.
*
* @param string $scheme
* @param string $target
* @param null|string $anchorName
* @return string
*/
protected function getInvalidLinkError($scheme, $target, $anchorName = null)
{
$url = "$scheme://$target" . ($anchorName ? '#' . $anchorName : '');

switch ($scheme) {
case 'eznode':
return sprintf('Invalid link "%s": target node cannot be found', $url);
case 'ezobject':
return sprintf('Invalid link "%s": target object cannot be found', $url);
default:
throw new InvalidArgumentException($scheme, "Given scheme '{$scheme}' is not supported.");
}
}
}
40 changes: 40 additions & 0 deletions lib/FieldType/XmlText/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/
namespace eZ\Publish\Core\FieldType\XmlText;

use eZ\Publish\API\Repository\Values\ContentType\FieldDefinition;
use eZ\Publish\Core\FieldType\FieldType;
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
use eZ\Publish\Core\FieldType\ValidationError;
Expand All @@ -36,6 +37,11 @@ class Type extends FieldType
*/
const TAG_PRESET_SIMPLE_FORMATTING = 1;

/**
* @var null|\eZ\Publish\Core\FieldType\XmlText\InternalLinkValidator
*/
protected $internalLinkValidator;

/**
* List of settings available for this FieldType.
*
Expand All @@ -54,6 +60,16 @@ class Type extends FieldType
),
);

/**
* Type constructor.
*
* @param null|\eZ\Publish\Core\FieldType\XmlText\InternalLinkValidator $internalLinkValidator
*/
public function __construct(InternalLinkValidator $internalLinkValidator = null)
{
$this->internalLinkValidator = $internalLinkValidator;
}

/**
* Returns the field type identifier for this field type.
*
Expand Down Expand Up @@ -245,6 +261,30 @@ public function isSearchable()
return true;
}

/**
* Validates a field.
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
*
* @param \eZ\Publish\API\Repository\Values\ContentType\FieldDefinition $fieldDefinition The field definition of the field
* @param \eZ\Publish\Core\FieldType\XmlText\Value $value The field value for which an action is performed
*
* @return \eZ\Publish\SPI\FieldType\ValidationError[]
*/
public function validate(FieldDefinition $fieldDefinition, SPIValue $value)
{
$validationErrors = array();

if ($this->internalLinkValidator !== null) {
$errors = $this->internalLinkValidator->validate($value->xml);
foreach ($errors as $error) {
$validationErrors[] = new ValidationError($error);
}
}

return $validationErrors;
}

/**
* Validates the fieldSettings of a FieldDefinitionCreateStruct or FieldDefinitionUpdateStruct.
*
Expand Down
3 changes: 3 additions & 0 deletions lib/settings/fieldtypes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ services:
ezpublish.fieldType.ezxmltext:
class: "%ezpublish.fieldType.ezxmltext.class%"
parent: ezpublish.fieldType
arguments:
- '@?ezpublish.fieldType.ezxmltext.validator.internal_link'
tags:
- {name: ezpublish.fieldType, alias: ezxmltext}

Loading

0 comments on commit 86f8cc0

Please sign in to comment.