Skip to content

Instantly share code, notes, and snippets.

@emodric
Created August 7, 2015 08:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save emodric/46c0fe8b17a081539e23 to your computer and use it in GitHub Desktop.
Save emodric/46c0fe8b17a081539e23 to your computer and use it in GitHub Desktop.
eZ Publish RelationList field type with location ID support
parameters:
ezpublish.fieldType.ezobjectrelationlist.class: Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Type
ezpublish.fieldType.ezobjectrelationlist.converter.class: Netgen\Bundle\HelperBundle\Core\Persistence\Legacy\Content\FieldValue\Converter\RelationList
<?php
namespace Netgen\Bundle\HelperBundle\Core\Persistence\Legacy\Content\FieldValue\Converter;
use eZ\Publish\Core\Persistence\Legacy\Content\FieldValue\Converter\RelationList as BaseRelationListConverter;
use eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition;
use eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldDefinition;
use eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue;
use eZ\Publish\SPI\Persistence\Content\FieldValue;
use DOMDocument;
class RelationList extends BaseRelationListConverter
{
/**
* @var \eZ\Publish\Core\Persistence\Database\DatabaseHandler
*/
protected $db;
/**
* Converts data from $value to $storageFieldValue
*
* @param \eZ\Publish\SPI\Persistence\Content\FieldValue $value
* @param \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue $storageFieldValue
*/
public function toStorageValue( FieldValue $value, StorageFieldValue $storageFieldValue )
{
$doc = new DOMDocument( '1.0', 'utf-8' );
$root = $doc->createElement( 'related-objects' );
$doc->appendChild( $root );
$relationList = $doc->createElement( 'relation-list' );
$data = $this->getRelationXmlHashFromDB( $value->data['destinationContentIds'] );
$priority = 0;
foreach ( $value->data['destinationContentIds'] as $key => $id )
{
$row = $data[$id][0];
$row["ezcontentobject_id"] = $id;
if ( !empty( $value->data['destinationLocationIds'][$key] ) )
{
$row["ezcontentobject_tree_node_id"] = $value->data['destinationLocationIds'][$key];
}
$row["priority"] = ( $priority += 1 );
$relationItem = $doc->createElement( 'relation-item' );
foreach ( self::dbAttributeMap() as $domAttrKey => $propertyKey )
{
if ( !isset( $row[$propertyKey] ) )
throw new \RuntimeException( "Missing relation-item external data property: $propertyKey" );
$relationItem->setAttribute( $domAttrKey, $row[$propertyKey] );
}
$relationList->appendChild( $relationItem );
unset( $relationItem );
}
$root->appendChild( $relationList );
$doc->appendChild( $root );
$storageFieldValue->dataText = $doc->saveXML();
}
/**
* Converts data from $value to $fieldValue
*
* @param \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldValue $value
* @param \eZ\Publish\SPI\Persistence\Content\FieldValue $fieldValue
*/
public function toFieldValue( StorageFieldValue $value, FieldValue $fieldValue )
{
$fieldValue->data = array(
'destinationContentIds' => array(),
'destinationLocationIds' => array()
);
if ( $value->dataText === null )
return;
$priorityByContentId = array();
$priorityByLocationId = array();
$dom = new DOMDocument( '1.0', 'utf-8' );
if ( $dom->loadXML( $value->dataText ) === true )
{
foreach ( $dom->getElementsByTagName( 'relation-item' ) as $relationItem )
{
/** @var \DOMElement $relationItem */
$priorityByContentId[$relationItem->getAttribute( 'contentobject-id' )] =
$relationItem->getAttribute( 'priority' );
$priorityByLocationId[$relationItem->getAttribute( 'node-id' )] =
$relationItem->getAttribute( 'priority' );
}
}
asort( $priorityByContentId, SORT_NUMERIC );
asort( $priorityByLocationId, SORT_NUMERIC );
$fieldValue->data['destinationContentIds'] = array_keys( $priorityByContentId );
$fieldValue->data['destinationLocationIds'] = array_keys( $priorityByLocationId );
}
/**
* Converts field definition data in $storageDef into $fieldDef
*
* <?xml version="1.0" encoding="utf-8"?>
* <related-objects>
* <constraints>
* <allowed-class contentclass-identifier="blog_post"/>
* </constraints>
* <type value="2"/>
* <selection_type value="1"/>
* <object_class value=""/>
* <contentobject-placement node-id="67"/>
* </related-objects>
*
* <?xml version="1.0" encoding="utf-8"?>
* <related-objects>
* <constraints/>
* <type value="2"/>
* <selection_type value="0"/>
* <object_class value=""/>
* <contentobject-placement/>
* </related-objects>
*
* @param \eZ\Publish\Core\Persistence\Legacy\Content\StorageFieldDefinition $storageDef
* @param \eZ\Publish\SPI\Persistence\Content\Type\FieldDefinition $fieldDef
*/
public function toFieldDefinition( StorageFieldDefinition $storageDef, FieldDefinition $fieldDef )
{
parent::toFieldDefinition( $storageDef, $fieldDef );
$fieldDef->defaultValue->data['destinationLocationIds'] = array();
}
/**
* @return array
*/
static private function dbAttributeMap()
{
return array(
// 'identifier' => 'identifier',// not used
'priority' => 'priority',
// 'in-trash' => 'in_trash',// false by default and implies
'contentobject-id' => 'ezcontentobject_id',
'contentobject-version' => 'ezcontentobject_current_version',
'node-id' => 'ezcontentobject_tree_node_id',
'parent-node-id' => 'ezcontentobject_tree_parent_node_id',
'contentclass-id' => 'ezcontentobject_contentclass_id',
'contentclass-identifier' => 'ezcontentclass_identifier',
// 'is-modified' => 'is_modified',// deprecated and not used
'contentobject-remote-id' => 'ezcontentobject_remote_id'
);
}
}
<?php
namespace Netgen\Bundle\HelperBundle\Core\FieldType\RelationList;
use eZ\Publish\Core\FieldType\RelationList\Type as BaseRelationListType;
use eZ\Publish\Core\Base\Exceptions\InvalidArgumentType;
use eZ\Publish\SPI\FieldType\Value as SPIValue;
use eZ\Publish\Core\FieldType\Value as BaseValue;
class Type extends BaseRelationListType
{
/**
* Returns the fallback default value of field type when no such default
* value is provided in the field definition in content types.
*
* @return \Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Value
*/
public function getEmptyValue()
{
return new Value();
}
/**
* Inspects given $inputValue and potentially converts it into a dedicated value object.
*
* @param int|string|array|\eZ\Publish\API\Repository\Values\Content\ContentInfo|\eZ\Publish\Core\FieldType\RelationList\Value $inputValue
*
* @return \Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Value The potentially converted and structurally plausible value.
*/
protected function createValueFromInput( $inputValue )
{
if ( is_array( $inputValue ) && isset( $inputValue['relation_list'] ) )
{
$relationList = $inputValue['relation_list'];
if ( !is_array( $relationList ) )
{
return $inputValue;
}
$destinationContentIds = array();
$destinationLocationIds = array();
foreach ( $relationList as $relationListItem )
{
if ( !isset( $relationListItem['content_id'] ) || !isset( $relationListItem['location_id'] ) )
{
return $inputValue;
}
if ( is_integer( $relationListItem['content_id'] ) || is_string( $relationListItem['content_id'] ) )
{
return $inputValue;
}
if ( is_integer( $relationListItem['location_id'] ) || is_string( $relationListItem['location_id'] ) )
{
return $inputValue;
}
$destinationContentIds[] = $relationListItem['content_id'];
$destinationLocationIds[] = $relationListItem['location_id'];
}
return new Value( $destinationContentIds, $destinationLocationIds );
}
return parent::createValueFromInput( $inputValue );
}
/**
* Throws an exception if value structure is not of expected format.
*
* @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException If the value does not match the expected structure.
*
* @param \Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Value $value
*/
protected function checkValueStructure( BaseValue $value )
{
parent::checkValueStructure( $value );
if ( !is_array( $value->destinationLocationIds ) )
{
throw new InvalidArgumentType(
"\$value->destinationLocationIds",
'array',
$value->destinationLocationIds
);
}
foreach ( $value->destinationLocationIds as $key => $destinationLocationId )
{
if ( !is_integer( $destinationLocationId ) && !is_string( $destinationLocationId ) )
{
throw new InvalidArgumentType(
"\$value->destinationLocationIds[$key]",
'string|int',
$destinationLocationId
);
}
}
}
/**
* Converts an $hash to the Value defined by the field type
*
* @param mixed $hash
*
* @return \Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Value $value
*/
public function fromHash( $hash )
{
return new Value( $hash['destinationContentIds'], $hash['destinationLocationIds'] );
}
/**
* Converts a $Value to a hash
*
* @param \Netgen\Bundle\HelperBundle\Core\FieldType\RelationList\Value $value
*
* @return mixed
*/
public function toHash( SPIValue $value )
{
return array(
'destinationContentIds' => $value->destinationContentIds,
'destinationLocationIds' => $value->destinationLocationIds
);
}
}
<?php
namespace Netgen\Bundle\HelperBundle\Core\FieldType\RelationList;
use eZ\Publish\Core\FieldType\RelationList\Value as BaseRelationListValue;
/**
* Value for RelationList field type
*/
class Value extends BaseRelationListValue
{
/**
* Related location IDs
*
* @var mixed[]
*/
public $destinationLocationIds;
/**
* Construct a new Value object and initialize it $text
*
* @param mixed[] $destinationContentIds
* @param mixed[] $destinationLocationIds
*/
public function __construct( array $destinationContentIds = array(), array $destinationLocationIds = array() )
{
parent::__construct( $destinationContentIds );
$this->destinationLocationIds = $destinationLocationIds;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment