Skip to content
Permalink
Browse files

Fix EZP-24800: Support "allowed classes" limitation for object relati…

…on fields (#1201)

* Fix EZP-24800: Support 'allowed classes' limitation for object relation (singular) fields

* Fix object relation browse mode class constraint list when no classes are selected
  • Loading branch information...
peterkeung authored and andrerom committed Aug 1, 2017
1 parent 1580a96 commit 1ce8043f8d7ef14d2c6156d73f564e34f8f66696
@@ -1,5 +1,7 @@
{* DO NOT EDIT THIS FILE! Use an override template instead. *}
{let content=$class_attribute.content}
{let content=$class_attribute.content
class_list=$content.class_constraint_list
all_class_list=fetch( 'class', 'list', hash( 'sort_by', array( 'name', true() ) ) )}

<div class="block">
<label for="eccaor_selection_{$class_attribute.id}">{'Selection method'|i18n( 'design/standard/class/datatype' )}:</label>
@@ -11,6 +13,16 @@
</select>
</div>

<div class="block">
<label for="eccaor_allowed_{$class_attribute.id}">{'Allowed classes'|i18n( 'design/standard/class/datatype' )}:</label>
<select id="eccaor_allowed_{$class_attribute.id}" name="ContentClass_ezobjectrelation_class_list_{$class_attribute.id}[]" multiple="multiple" title="{'Select which classes user can create'|i18n( 'design/standard/class/datatype' )}" size="{min( 8, count( $all_class_list ) )}">
<option value="" {if $class_list|lt(1)}selected="selected"{/if}>{'Any'|i18n( 'design/standard/class/datatype' )}</option>
{section name=Class loop=$all_class_list}
<option value="{$:item.identifier|wash}" {if $class_list|contains($:item.identifier)}selected="selected"{/if}>{$:item.name|wash}</option>
{/section}
</select>
</div>

<div class="block">
<fieldset>
<legend>{'Default selection item'|i18n( 'design/standard/class/datatype' )}</legend>
@@ -7,6 +7,18 @@
<p>{$content.selection_type|choose( 'Browse'|i18n( 'design/standard/class/datatype' ), 'Drop-down list'|i18n( 'design/standard/class/datatype' ), 'Drop-down tree'|i18n( 'design/standard/class/datatype' ) )}</p>
</div>

{* Allowed classes. *}
<div class="block">
<label>{'Allowed classes'|i18n( 'design/standard/class/datatype' )}:</label>
{section show=$content.class_constraint_list|count|lt( 1 )}
<p>{'Any'|i18n( 'design/standard/class/datatype' )}</p>
{section-else}
<ul>
{section var=Classes loop=$content.class_constraint_list}<li>{$Classes.item}</li>{/section}
</ul>
{/section}
</div>

{* Selection item/node. *}
<div class="block">
<label>{'Default selection item'|i18n( 'design/standard/class/datatype' )}:</label>
@@ -55,6 +55,9 @@
{if $attribute.class_content.default_selection_node}
<input type="hidden" name="{$attribute_base}_browse_for_object_start_node[{$attribute.id}]" value="{$attribute.class_content.default_selection_node|wash}" />
{/if}
{if is_set( $class_content.class_constraint_list[0] )}
<input type="hidden" name="{$attribute_base}_browse_for_object_class_constraint_list[{$attribute.id}]" value="{$class_content.class_constraint_list|implode(',')}" />
{/if}
{if $attribute.content}
<input class="button ezobject-relation-remove-button" type="submit" name="CustomActionButton[{$attribute.id}_remove_object]" value="{'Remove object'|i18n( 'design/standard/content/datatype' )}" />
{else}
@@ -88,14 +91,27 @@
{* Dropdown list. *}
{case match=1}
{let parent_node=fetch( content, node, hash( node_id, $class_content.default_selection_node ) )}

{def $nodesList=cond( and( is_set( $class_content.class_constraint_list ), $class_content.class_constraint_list|count|ne( 0 ) ),
fetch( 'content', 'list',
hash( 'parent_node_id', $parent_node.node_id,
'class_filter_type','include',
'class_filter_array', $class_content.class_constraint_list,
'sort_by', $parent_node.sort_array
) ),
fetch( 'content', 'list',
hash( 'parent_node_id', $parent_node.node_id,
'sort_by', $parent_node.sort_array )
) )

This comment has been minimized.

@volkanakb

volkanakb Oct 20, 2017

Contributor

3 closing parentheses instead of two

This comment has been minimized.

@andrerom

andrerom Oct 20, 2017

Member

Indeed, are you able to open PR on this one? Simplest is editing it right here on github, should be ok for things like this, if you are not so confortable doing it with full checkout and clone and such.

)}
<select id="ezcoa-{if ne( $attribute_base, 'ContentObjectAttribute' )}{$attribute_base}-{/if}{$attribute.contentclassattribute_id}_{$attribute.contentclass_attribute_identifier}" class="ezcc-{$attribute.object.content_class.identifier} ezcca-{$attribute.object.content_class.identifier}_{$attribute.contentclass_attribute_identifier}" name="{$attribute_base}_data_object_relation_id_{$attribute.id}">
{if $attribute.contentclass_attribute.is_required|not}
<option value="" {if eq( $attribute.data_int, '' )}selected="selected"{/if}>{'No relation'|i18n( 'design/standard/content/datatype' )}</option>
{/if}
{section var=Nodes loop=fetch( content, list, hash( parent_node_id, $parent_node.node_id, sort_by, $parent_node.sort_array ) )}
<option value="{$Nodes.item.contentobject_id}" {if eq( $attribute.data_int, $Nodes.item.contentobject_id )}selected="selected"{/if}>{$Nodes.item.name|wash}</option>
{/section}
{if $nodesList}
{foreach $nodesList as $nodeOption}
<option value="{$nodeOption.contentobject_id}" {if eq( $attribute.data_int, $nodeOption.contentobject_id )}selected="selected"{/if}>{$nodeOption.name|wash()}</option>
{/foreach}
{/if}
</select>

{if $class_content.fuzzy_match}
@@ -149,6 +149,72 @@ function fuzzyTextMatch( $text, $match )
return false;
}
function storeClassAttributeContent( $classAttribute, $content )
{
if ( is_array( $content ) )
{
$doc = $this->createClassDOMDocument( $content );
$this->storeClassDOMDocument( $doc, $classAttribute );
return true;
}
return false;
}
static function storeClassDOMDocument( $doc, $classAttribute )
{
$docText = self::domString( $doc );
$classAttribute->setAttribute( 'data_text5', $docText );
}
static function storeObjectDOMDocument( $doc, $objectAttribute )
{
$docText = self::domString( $doc );
$objectAttribute->setAttribute( 'data_text', $docText );
}
/*!
\static
\return the XML structure in \a $domDocument as text.
It will take of care of the necessary charset conversions
for content storage.
*/
static function domString( $domDocument )
{
$ini = eZINI::instance();
$xmlCharset = $ini->variable( 'RegionalSettings', 'ContentXMLCharset' );
if ( $xmlCharset == 'enabled' )
{
$charset = eZTextCodec::internalCharset();
}
else if ( $xmlCharset == 'disabled' )
$charset = true;
else
$charset = $xmlCharset;
if ( $charset !== true )
{
$charset = eZCharsetInfo::realCharsetCode( $charset );
}
$domString = $domDocument->saveXML();
return $domString;
}
static function createClassDOMDocument( $content )
{
$doc = new DOMDocument( '1.0', 'utf-8' );
$root = $doc->createElement( 'related-object' );
$constraints = $doc->createElement( 'constraints' );
foreach ( $content['class_constraint_list'] as $constraintClassIdentifier )
{
unset( $constraintElement );
$constraintElement = $doc->createElement( 'allowed-class' );
$constraintElement->setAttribute( 'contentclass-identifier', $constraintClassIdentifier );
$constraints->appendChild( $constraintElement );
}
$root->appendChild( $constraints );
$doc->appendChild( $root );
return $doc;
}
/*!
Stores relation to the ezcontentobject_link table
*/
@@ -213,6 +279,19 @@ function fetchClassAttributeHTTPInput( $http, $base, $classAttribute )
{
$selectionTypeName = 'ContentClass_ezobjectrelation_selection_type_' . $classAttribute->attribute( 'id' );
$content = $classAttribute->content();
$postVariable = 'ContentClass_ezobjectrelation_class_list_' . $classAttribute->attribute( 'id' );
if ( $http->hasPostVariable( $postVariable ) )
{
$constrainedList = $http->postVariable( $postVariable );
$constrainedClassList = array();
foreach ( $constrainedList as $constraint )
{
if ( trim( $constraint ) != '' )
$constrainedClassList[] = $constraint;
}
$content['class_constraint_list'] = $constrainedClassList;
$hasData = true;
}
$hasData = false;
if ( $http->hasPostVariable( $selectionTypeName ) )
{
@@ -239,12 +318,33 @@ function fetchClassAttributeHTTPInput( $http, $base, $classAttribute )
return false;
}
function initializeClassAttribute( $classAttribute )
{
$xmlText = $classAttribute->attribute( 'data_text5' );
if ( trim( $xmlText ) == '' )
{
$content = $this->defaultClassAttributeContent();
return $this->storeClassAttributeContent( $classAttribute, $content );
}
}
function preStoreClassAttribute( $classAttribute, $version )
{
$content = $classAttribute->content();
$classAttribute->setAttribute( 'data_int1', $content['selection_type'] );
$classAttribute->setAttribute( 'data_int2', $content['default_selection_node'] );
$classAttribute->setAttribute( 'data_int3', $content['fuzzy_match'] );
$xmlContentArray = array();
$defaultClassAttributeContent = $this->defaultClassAttributeContent();
foreach( $content as $xmlKey => $xmlContent )
{
if( isset( $defaultClassAttributeContent[$xmlKey] ) )
{
$xmlContentArray[$xmlKey] = $xmlContent;
}
}
$this->storeClassAttributeContent( $classAttribute, $xmlContentArray );
}
/*!
@@ -335,6 +435,25 @@ function customObjectAttributeHTTPAction( $http, $action, $contentObjectAttribut
if ( isset( $nodePlacement[$contentObjectAttribute->attribute( 'id' )] ) )
$browseParameters['start_node'] = eZContentBrowse::nodeAliasID( $nodePlacement[$contentObjectAttribute->attribute( 'id' )] );
}
// Fetch the list of "allowed" classes .
// A user can select objects of only those allowed classes when browsing.
$classAttribute = $contentObjectAttribute->attribute( 'contentclass_attribute' );
$classContent = $classAttribute->content();
if ( isset( $classContent['class_constraint_list'] ) )
{
$classConstraintList = $classContent['class_constraint_list'];
}
else
{
$classConstraintList = array();
}
if ( count($classConstraintList) > 0 )
{
$browseParameters['class_array'] = $classConstraintList;
}
eZContentBrowse::browse( $browseParameters,
$module );
} break;
@@ -368,6 +487,18 @@ function objectAttributeContent( $contentObjectAttribute )
return $object;
}
static function parseXML( $xmlText )
{
$dom = new DOMDocument( '1.0', 'utf-8' );
$dom->loadXML( $xmlText );
return $dom;
}
function defaultClassAttributeContent()
{
return array( 'class_constraint_list' => array() );
}
/*!
Sets \c grouped_input to \c true when browse mode is active or
a dropdown with a fuzzy match is used.
@@ -399,16 +530,43 @@ function classAttributeContent( $classObjectAttribute )
$selectionType = $classObjectAttribute->attribute( "data_int1" );
$defaultSelectionNode = $classObjectAttribute->attribute( "data_int2" );
$fuzzyMatch = $classObjectAttribute->attribute( "data_int3" );
return array( 'selection_type' => $selectionType,
'default_selection_node' => $defaultSelectionNode,
'fuzzy_match' => $fuzzyMatch );
$attributeContent = array( 'selection_type' => $selectionType,
'default_selection_node' => $defaultSelectionNode,
'fuzzy_match' => $fuzzyMatch );
$attributeXMLContent = $this->defaultClassAttributeContent();
$xmlText = $classObjectAttribute->attribute( 'data_text5' );
if ( trim( $xmlText ) != '' )
{
$doc = $this->parseXML( $xmlText );
$attributeXMLContent = $this->createClassContentStructure( $doc );
}
return array_merge( $attributeContent, $attributeXMLContent );
}
function deleteNotVersionedStoredClassAttribute( eZContentClassAttribute $classAttribute )
{
eZContentObjectAttribute::removeRelationsByContentClassAttributeId( $classAttribute->attribute( 'id' ) );
}
function createClassContentStructure( $doc )
{
$content = $this->defaultClassAttributeContent();
$root = $doc->documentElement;
$constraints = $root->getElementsByTagName( 'constraints' )->item( 0 );
if ( $constraints )
{
$allowedClassList = $constraints->getElementsByTagName( 'allowed-class' );
foreach( $allowedClassList as $allowedClass )
{
$content['class_constraint_list'][] = $allowedClass->getAttribute( 'contentclass-identifier' );
}
}
return $content;
}
function customClassAttributeHTTPAction( $http, $action, $classAttribute )
{
switch ( $action )

0 comments on commit 1ce8043

Please sign in to comment.
You can’t perform that action at this time.