Forums / Developer / "are_related" template operator

"are_related" template operator

Author Message

Mickael Robin

Tuesday 31 March 2009 1:53:03 am

Hi,

I need to implement "if A and B are related..."

I didn't find any native operator for this purpose, but I found 2 ways to explore :

1st way : fetch the objects that are related to A, and check if the array contains B's content_object_id
=> I don't know how to inspect the array produced by the related_objects fetch with the "contains" template operator...

2nd way : make an SQL query directly on ezcontentobject_link table
=> this might be more effective, but seems to require more eZ and SQL knowledge to create a custom operator...

3rd way : ?

Does anyone have an advice on the question?

Thanks in advance,

Mickael

André R.

Tuesday 31 March 2009 2:18:43 am

2 is definitively the most effective.

What is the use case for this?
Normally you'll want to view the relations of the current object your viewing, in what cases do you need to know relation but do not need to fetch any of the objects?

Because if your already fetch the object then something like this in a template operator (php) might be most effective without having to write your own sql.

$object = eZContentObject::fetch( $namedParameters['object_id'] );// either this or passing object as parameter
$relArray = $object->relatedObjects( false, false, 0, array( 'AsObject' => false ) );
$operatorValue = false;
// loop over array and compare with second parameter for related-to-id
// and set $operatorValue to true and break the loop if you find a match

Example of simple template operator:
http://svn.ez.no/svn/extensions/eztinymce/trunk/ezoe/autoloads/eztemplateautoload.php
http://svn.ez.no/svn/extensions/eztinymce/trunk/ezoe/autoloads/ezoetemplateutils.php

eZ Online Editor 5: http://projects.ez.no/ezoe || eZJSCore (Ajax): http://projects.ez.no/ezjscore || eZ Publish EE http://ez.no/eZPublish/eZ-Publish-Enterprise-Subscription
@: http://twitter.com/andrerom

Mickael Robin

Tuesday 31 March 2009 2:32:31 am

Hi Andre,
and thanks for your quick and useful help :-)
I'm gonna try and create my first template operator !

To answer your question about the use case : I am working on http://www.spotilinks.co.uk , a social web app to manage and discover music for Spotify (that I strongly recommend to your ears !!!)

Each member (folder-like class, not user) is invited to select other members to receive their recent playlists.
=> as this selection is managed with an object_relations attribute, if need to check if a member is already related to the one he visits, so he can not select it twice.

Mickael Robin

Tuesday 31 March 2009 6:04:38 am

I think I managed creating my "arerelated" operator but I can't find how to pass the paraméters from template.

<b>1\ Installation seems OK...</b>
I added the code below in \extension\ezwebin\autoloads\eztemplateautoload.php:

$eZTemplateOperatorArray[] = array( 'script' => 'extension/ezwebin/autoloads/arerelated.php',
                                    'class' => 'arerelated',
                                    'operator_names' => array( 'arerelated' ) );

And I regenerated autoload arrays from the admin interface, after creating the following template operator.

<b>2\ Operator should work...</b>
Then I created extension\ezwebin\autoloads\arerelated.php with this code :
<?php
class arerelated
{
function arerelated()
{
}

function operatorList()
{
return array( 'arerelated' );
}

function namedParameterPerOperator()
{
return true;
}

function namedParameterList()
{
return array( 'arerelated' => array( 'object_id_from' => array( 'type' => 'integer',
'required' => true,
'default' => '' ),
'object_id_to' => array( 'type' => 'integer',
'required' => true,
'default' => '' )
) );
}

function modify( $tpl, $operatorName, $operatorParameters, &$rootNamespace, &$currentNamespace, &$operatorValue, &$namedParameters )
{
$object_id_from = $namedParameters['object_id_from'];
$object_id_to = $namedParameters['object_id_to'];

switch ( $operatorName )
{
case 'arerelated':
{
$object_from = eZContentObject::fetch( $object_id_from );
$object_to = eZContentObject::fetch( $object_id_to);
$relArray = $object_from->relatedObjects( false, false, 0, array( 'AsObject' => false ) );
$operatorValue = false;

// loop over array and compare with second parameter for related-to-id
// and set $operatorValue to true and break the loop if you find a match
foreach( $relArray as $rel )
{
if( $rel == $object_id_to )
{
$operatorValue = true;
break;
}
}

}
}
}
}

?>

</code>One question yet : am I supposed to <b>compare objects or object_ids</b> ???

<b>3\ I can't pass the parameters</b>

Now, my problem is that I can't find the template syntax to pass the NamedParameters to my new operator.

I tried :

{if arerelated(array('object_id_from', $member_node.contentobject_id, 'object_id_to', $node.contentobject_id ))}

and

{if arerelated(hash('object_id_from', $member_node.contentobject_id, 'object_id_to', $node.contentobject_id ))}

but I think I am <b>lost within arrays</b>, despite deep survey of existing documentation and code analysis :-(

Thanks in advance for your help :-)

André R.

Tuesday 31 March 2009 8:03:52 am

No, use 'var_dump' on $rel and you'll see what parameters you get.

And you do not need the $object_to line.

(hint: 'id')

Note: when you move this out of ezwebin later, you'll need to define the extension you move it into with site.ini [TemplateSettings]ExtensionAutoloadPath[]=your_extension_name.

Note 2: you should call it like {if arerelated( $member_node.contentobject_id, $node.contentobject_id )}

eZ Online Editor 5: http://projects.ez.no/ezoe || eZJSCore (Ajax): http://projects.ez.no/ezjscore || eZ Publish EE http://ez.no/eZPublish/eZ-Publish-Enterprise-Subscription
@: http://twitter.com/andrerom

Mickael Robin

Tuesday 31 March 2009 10:08:21 am

Thanks a lot André,

I could not make it with "->relatedObjects" but the "relatedContentObjectArray" function did the work.

As I had to filter on an attribute_id, I added a NamedParameter to the code below.

As a result, here's the content of my "arerelated.php" :

<?php

class arerelated
{
    function arerelated()
    {
    }

    function operatorList()
    {
        return array( 'arerelated' );
    }

    function namedParameterPerOperator()
    {
        return true;
    }

    function namedParameterList()
    {
        return array( 'arerelated' => array( 'object_id_from' => array( 'type' => 'integer',
                                                               'required' => true,
                                                               'default' => ''),
                                             'object_id_to' => array( 'type' => 'integer',
                                                                'required' => true,
                                                                'default' => '' ),
						'attribute_id' => array( 'type' => 'integer',
                                                                'required' => true,
                                                                'default' => '' )
       					 ) );
    }

    function modify( $tpl, $operatorName, $operatorParameters, &$rootNamespace, &$currentNamespace, &$operatorValue, &$namedParameters )
    {
        $object_id_from = $namedParameters['object_id_from'];
        $object_id_to = $namedParameters['object_id_to'];
        $attribute_id = $namedParameters['attribute_id'];

        
        switch ( $operatorName )
        {
            case 'arerelated':
            {
				$object_from = eZContentObject::fetch( $object_id_from );					            		
//				$relArray = $object_from->relatedObjects( false, $object_id_from, 0, false, false, false );
				$relArray = $object_from->relatedContentObjectArray( false , false, $attribute_id, false );
				$operatorValue = false;

// loop over array and compare with second parameter for related-to-id
// and set $operatorValue to true and break the loop if you find a match
            foreach ( $relArray as $rel )
				{
					$rel_id = $rel->ID;				
   					if( $rel_id == $object_id_to )
    				{
					$operatorValue = true;
    					break;
    				}
				}				

            } 
        }
    }
}

?>

And to call it from my template, I use :

{if arerelated($member_node.contentobject_id, $node.contentobject_id, '386' )}

where 386 is the attibute_id I want to filter on

I'm glad I'me done and I hope this will help others as much André helped me :-)