Forums / Developer / Multiple classes, common attribute fetch

Multiple classes, common attribute fetch

Author Message

Luis Micunco

Tuesday 05 May 2009 2:04:16 am

Hi,
I know this topic is repeated, but i havent found a solution.

Quoting from the fetch function list documentation:

"It is not possible to filter on attributes of different classes, for example it is not possible to filter on both "article/show_comments" and "folder/show_comments" in the same filter. "

Isnt there an good way to achieve this yet?. Im in a situation where i need to do a fetch from a php function to get objects from 2 different classes, like: "images, maps". those classes has a common "selection" attribute called: "category" .

I tried this:

$fetchParams = array( 
	 'ClassFilterType' => 'include', 
	 'ClassFilterArray' => array(30, 54) ,
	 'AttributeFilter' => array( 'or',
	        array(342, "=", 3),
		array(531, "=", 3 )
	 ) );

  $result = eZContentObjectTreeNode::subTreeCountByNodeID( $fetchParams, 221 );

The fetch returns in no results, but works fine by removing the statement.

array(531, "=", 3 )

Thank you.

Ivo Lukac

Tuesday 05 May 2009 2:22:16 am

Hello,

You can do this only using custom extended attribute filter. I will try to find an example and post it here

http://www.linkedin.com/in/ivolukac
http://www.netgen.hr/eng/blog
http://twitter.com/ilukac

Ivo Lukac

Tuesday 05 May 2009 2:38:35 am

Found something for ez3 (php4). If you working with ez4 (php5) you will need to modify the constructor call.
This filter is used for objectrelation attribute, but you can make it to work with selection attribute.

Make a new extension with file kernel\classes\ezcategoryfilter.php

<?php

class eZExtendedCategoryFilter
{
    /*!      Constructor     */
    function eZExtendedCategoryFilter()
    {
    }

    function createSqlParts( $params )
    {
        $result = array( 'tables' => '', 'joins'  => '' );

        if ( isset( $params['classes'] ) )
        {
             $classes = $params['classes'];
        } else
		return;

        $filterSQL = array();
        $filterSQL['from']  = ", ezcontentobject_link i1 ";

	$attribute_ids = array();
	foreach ($classes as $class) {
			array_push($attribute_ids,eZContentObjectTreeNode::classAttributeIDByIdentifier( $class . '/category' ));
	}
	$class_cond = array();
	foreach ($attribute_ids as $aid) {
		if ($aid) {
		array_push($class_cond, 'i1.contentclassattribute_id = '.$aid);
		}
	}

        $string_class_cond = implode(" OR ",$class_cond);

        $filterSQL['where'] = " ( i1.from_contentobject_id = ezcontentobject.id AND (" . $string_class_cond . ") AND 			   i1.from_contentobject_version = ezcontentobject.current_version AND i1.to_contentobject_id = " . $params['object_id'] . ") AND ";

	return array( 'tables' => $filterSQL['from'], 'joins'  => $filterSQL['where'] );

    }
}

?>

Also add this to extendedattributefilter.ini:

[ExtendedCategoryFilter]
#The name of the extension where the filtering code is defined.
ExtensionName=your_extension

#The name of the filter class.
ClassName=eZExtendedCategoryFilter

#The name of the method which is called to generate the SQL parts.
MethodName=createSqlParts

#The file which should be included (extension/myextension will automatically be prepended).
FileName=kernel/classes/ezcategoryfilter.php

And activate the extension.
You then use this in your templates like this:

fetch( 'content', 'tree', hash( parent_node_id, $parent_node_id ,
'extended_attribute_filter', hash('id','ExtendedCategoryFilter','params',hash('object_id', $value,'classes',array('class1','class2'))),	))}

http://www.linkedin.com/in/ivolukac
http://www.netgen.hr/eng/blog
http://twitter.com/ilukac

Luis Micunco

Tuesday 05 May 2009 3:22:06 am

Hi.
I will give it a try.

Thanks a lot.

Luis Micunco

Friday 08 May 2009 1:39:11 am

Hi.
Now i got it to work.
But what about the "sort by". I need also to "sort" the result by a "date" attribute. Again its is a common attribute in both classes with the same identifier.

Is it possible to include an "ORDER BY" o something similiar in the code ?.
Thank you. I will post my result code later.

Ivo Lukac

Friday 08 May 2009 1:56:09 am

In extended attribute filter you are attaching some SQL parts to ez query so you probably can add your 'order by'

http://www.linkedin.com/in/ivolukac
http://www.netgen.hr/eng/blog
http://twitter.com/ilukac

Luis Micunco

Friday 08 May 2009 2:01:08 am

Yes.
I think there is a default "ORDER BY" value.
Looking at the MYSQL DEBUG of my fetch, it appends:

"ORDER BY path_string ASC"

Any idea? Thank you

Ivo Lukac

Friday 08 May 2009 3:37:58 am

Hm, just checked some code, and it seems it can't be done.
createSqlParts function returns 'tables' and 'joins' and that's it.

There is no extended sorting :(

http://www.linkedin.com/in/ivolukac
http://www.netgen.hr/eng/blog
http://twitter.com/ilukac

Peter Halasz

Monday 11 May 2009 1:37:16 am

Actually you can return columns as well. The docs don't say it but you can have a colums part for the return array, then you can have the ORDER BY to order by that custom column as well.

Check this for clarification http://pubsvn.ez.no/doxygen/4.0/html/ezcontentobjecttreenode_8php-source.html#l00870

Ivo Lukac

Monday 11 May 2009 3:16:39 am

You mean like sending with columns variable additional attribute with AS FOOBAR, and then in fetch sort it with 'FOOBAR'?

Hm, could work, but I don't have time to experiment :/

http://www.linkedin.com/in/ivolukac
http://www.netgen.hr/eng/blog
http://twitter.com/ilukac

Peter Halasz

Tuesday 12 May 2009 3:53:48 pm

Yup exactly :)

Luis Micunco

Wednesday 13 May 2009 10:19:11 am

Hi there again.
This worked for the sorting:

fetch( 'content', 'tree', hash( parent_node_id, $parent_node_id ,
'sort_by', array(array('i1.sort_key_int', 0)),
'extended_attribute_filter', hash('id','ExtendedCategoryFilter','params',hash('object_id', $value,'classes',array('class1','class2'))), ))}

I think this is because "i1" is the "ezcontentobject_attribute" alias, and "sort_key_int" the "ezcontentobject_attribute" field im sorting by.
I will post the entire code then-
Thanks to all

Benjamin Lorteau

Saturday 23 May 2009 3:44:57 am

Hey Luis,

I just stumble upon the very same problem as you, and it seems that you found your way through. Could you share your solution ?

Thanks in advance !

Benjamin

eZ Publish personal project : http://www.aeriesguard.com [fr]

Clemens T

Wednesday 29 July 2009 6:25:20 am

Benjamin, and others,

Maybe I'm too late, but here's my extende PHP filter. First off, important to know is that I have multiple classes that share a category string. A dropdown box in my case is used to filter through these categories, hence the 'LIKE' statement (categories can be added just by typing text and separating by comma's).

Here's my code (based on previous steps discussed in this thread):

<?php    
class eZExtendedCategoryFilter
{    
	/*!     Constructor    */    
	function eZExtendedCategoryFilter()
	{     
	}       
	 
	function createSqlParts( $params )     
	{         
		$result = array( 'tables' => '', 'joins' => '' );           
		if ( isset( $params['classes'] ) )        
		{              
			$classes = $params['classes'];         
		} 
		else                  
		  return; 
	  
	  	$filterSQL = array();         
	  	$filterSQL['from'] = ", ezcontentobject_attribute ";            
	  	$attribute_ids = array();          
  
		foreach ($classes as $class) {                          
			array_push($attribute_ids,eZContentObjectTreeNode::classAttributeIDByIdentifier( $class . '/categories' ));          
		}          
		
		$class_cond = array();          
		foreach ($attribute_ids as $aid)
		{                  
			if ($aid)
			{                  
				array_push($class_cond, 'ezcontentobject_attribute.contentclassattribute_id = '.$aid);                  
			}          
		}           
		
		$string_class_cond = implode(" OR ",$class_cond);
		$filterSQL['where'] = " ( ezcontentobject_attribute.contentobject_id = ezcontentobject.id AND (" . 
								$string_class_cond . 
								") AND ezcontentobject_attribute.version = ezcontentobject.current_version "
								." AND ezcontentobject_attribute.data_text LIKE '%" . 
								$params['textLIKEfilter'] . 
								"%') AND ";   
		
		return array( 'tables' => $filterSQL['from'], 'joins' => $filterSQL['where'] );       
	}  
}    
?>

And the template function looks like this:

{def $list=fetch('content','list',hash('parent_node_id',$myNodeID, 
												offset, $#view_parameters.offset, 
												sort_by, array( 'priority', false()), 
												limit, 5,	
												'extended_attribute_filter', hash('id','ExtendedCategoryFilter',
																				'params',
																					hash(	'textLIKEfilter', ezhttp('categories', 'get'),
																							'classes',array('class1','class2')
																				)
																			)									
												))}

Hopefully this helps you, and others.

Benjamin Lorteau

Wednesday 29 July 2009 6:42:21 am

Hey Clemens, thanks for you filter, which seems to open an interesting way to filter on multiple classes. I should use it one way or another next time I stumble upon the same problem.

Oh, and by the way, you shouldn't use ezhttp operator in your template if it's a view template, use View Parameters instead ;-)

eZ Publish personal project : http://www.aeriesguard.com [fr]

quang lam

Friday 21 January 2011 3:22:00 am

Hi

I was only interested by sorting on different attributes in differents classes within a fetch

Base on previous posts, I was able to correct the code ( EZ v 4.x) in this purpose :

<?php

class eZExtendedCategoryFilter
{
    /*!      Constructor     */
    function eZExtendedCategoryFilter()
    {
    }

    function createSqlParts( $params )
    {
        $result = array( 'tables' => '', 'joins'  => '' );

        if ( isset( $params['classes'] ) )
        {
             $classes = $params['classes'];
        } else
        return;
        
        if ( isset( $params['sort_fields'] ) )
        {
             $sort_fields = $params['sort_fields'];
        } else
        return;

        $filterSQL = array();
        $filterSQL['from']  = ", ezcontentobject_attribute  ";

    $attribute_ids = array();
    $i=0;
    foreach ($classes as $class) {
            array_push($attribute_ids,eZContentObjectTreeNode::classAttributeIDByIdentifier( $class . '/'.$sort_fields[$i] ));
            $i++;
    }
    $class_cond = array();
    foreach ($attribute_ids as $aid) {
        if ($aid) {
        array_push($class_cond, 'ezcontentobject_attribute.contentclassattribute_id = '.$aid);
        }
    }

        $string_class_cond = implode(" OR ",$class_cond);

        $filterSQL['where'] = " ( ezcontentobject_attribute.contentobject_id = ezcontentobject.id AND (" . $string_class_cond . ") AND                ezcontentobject_attribute.version = ezcontentobject.current_version ". ") AND ";

    return array( 'tables' => $filterSQL['from'], 'joins'  => $filterSQL['where'] );

    }
}

?>

Template call

{def $news=fetch( 'content', 'tree', hash( parent_node_id, $parent_node_id ,
'limit',$nbnews,
'sort_by', array(array('ezcontentobject_attribute.data_int', 0)),
'extended_attribute_filter', hash('id','ExtendedCategoryFilter','params',hash('classes',array('press','article_mainpage'),'sort_fields',array('date','publish_date')))
))
  • sort_by : put the data type of the attributes. i.e my attributes were date. they are store as data_int en EZ
  • params :
    classes : put the class names ,
    sort_fields: put the user defined identifiers on which the sort should run, in the same order as class names.
    i.e . I have two classes ( press - field identifier : date / article_mainpage - field identifier : publish_date )

Thanks everyone for helping me to write this "missing" feature

gilles guirand

Sunday 23 January 2011 1:10:19 pm

And also, you could use eZ Find :

{def $search=fetch( ezfind, search,
     hash( query , '',
           'class_id', array('press','article_mainpage'),
           'limit', 10,
           'sort_by', hash('attr_date_dt', 'desc')
))}

--
Gilles Guirand
eZ Community Board Member
http://twitter.com/gandbox
http://www.gandbox.fr