Magento – Creating a New, Custom Filter for Dataflow Exports

dataflowexportfilterproduct

I am trying to add some custom filters to the Dataflow export in Magento. First up, is exporting products with no images.

I created app/code/local/Mage/Mycompany/Model/Catalog/Convert/Adapter/Product.php

class Mage_Mycompany_Model_Catalog_Convert_Adapter_Product
    extends Mage_Catalog_Model_Convert_Adapter_Product
{
    /**
     * Load product collection Id(s)
     */
    public function load()
    {
        parent::load();

        $filters = $this->_parseVars();

        if (isset($filters['hasImage'])) {
            $hasImage = (bool)$filters['hasImage'];

            try {
                /*
                 * Try to filter by the image field.
                 * See one of the three options below...
                 */
            } catch (Exception $e) {
                $message = Mage::helper('eav')->__('There was a problem filtering by `hasImage`. Error: %s', $e->getMessage());
                $this->addException($message, Varien_Convert_Exception::FATAL);
            }
        }

        return $this;
    }
}

In my profile XML, I changed
<action type="catalog/convert_adapter_product" method="load">
to
<action type="mycompany/catalog_convert_adapter_product" method="load">
and added
<var name="filter/hasImage"><![CDATA[1]]></var>

Failed filter #1

$filterArray = array();
$filterArray['alias']       = 'hasImage';
$filterArray['attribute']   = 'catalog_product/entity_varchar';
$filterArray['field']       = 'value';
$filterArray['bind']        = 'product_id=entity_id';
$filterArray['joinType']    = 'inner';

if ($hasImage) {
    $filterArray['cond'] = "{{table}}.attribute_id = 106 AND {{table}}.value != 'no_selection' AND {{table}}.value IS NOT NULL";
} else {
    $filterArray['cond'] = "{{table}}.attribute_id = 106 AND ({{table}}.value = 'no_selection' OR {{table}}.value IS NULL)";
}

$this->setJoinField($filterArray);

Failed filter #2

if ($hasImage) {
    $this->_filter[] = array(
        'attribute' => 'hasImage',
        'notnull'   => 1,
        'neq'       => 'no_selection'
    );
} else {
    $this->_filter[] = array(
        'attribute' => 'hasImage',
        'null'      => 1
    );
    $this->_filter[] = array(
        'attribute' => 'hasImage',
        'eq'        => 'no_selection'
    );
}

$this->setJoinAttr(array(
    'alias'     => 'hasImage',
    'attribute' => 'catalog_product/entity_varchar',
    'bind'      => 'entity_id',
    //'cond'      => array('notnull'=>'','neq'=>'no_selection'),
    'cond'      => "{{table}}.attribute_id = 106",
    'joinType'  => 'inner'
));

Failed filter #3

if (!($entityType = $this->getVar('entity_type'))
|| !(Mage::getResourceSingleton($entityType) instanceof Mage_Eav_Model_Entity_Interface)) {
    $this->addException(Mage::helper('eav')->__('Invalid entity specified'), Varien_Convert_Exception::FATAL);
}

$collection = $this->_getCollectionForLoad($entityType);

$parentEntityIds = $collection->getAllIds();

if ($hasImage) {
    $hasImageFilter = array('notnull'=>'', 'neq'=>'no_selection');
    $collection
        ->addAttributeToFilter('image', $hasImageFilter)
        ->addAttributeToFilter('small_image', $hasImageFilter)
        ->addAttributeToFilter('thumbnail', $hasImageFilter);
} else {
    $collection
        ->addAttributeToFilter(array(
            array('attribute' => 'image', 'null' => 1),
            array('attribute' => 'image', 'eq' => 'no_selection')
        ))
        ->addAttributeToFilter(array(
            array('attribute' => 'small_image', 'null' => 1),
            array('attribute' => 'small_image', 'eq' => 'no_selection')
        ))
        ->addAttributeToFilter(array(
            array('attribute' => 'thumbnail', 'null' => 1),
            array('attribute' => 'thumbnail', 'eq' => 'no_selection')
        ));
}

/**
 * Load collection ids
 */
$thisEntityIds = $collection->getAllIds();

$entityIds = array_intersect($parentEntityIds, $thisEntityIds);

$this->setData($entityIds);

I know that this code is being hit. I can die('here'); and that works. But it's not having the desired filtering affect at all.

I can't find a single tutorial on creating custom filters for Dataflow, so any help is appreciated.

Best Answer

This is how I eventually solved my problem:

class Mage_Mymodule_Model_Catalog_Convert_Adapter_Product
    extends Mage_Catalog_Model_Convert_Adapter_Product
{
    /**
     * Load product collection Id(s)
     */
    public function load()
    {
        parent::load();

        $filters = $this->_parseVars();

        if (isset($filters['hasImage'])) {
            $hasImage = (bool)$filters['hasImage'];

            try {
                if (!($entityType = $this->getVar('entity_type'))
                || !(Mage::getResourceSingleton($entityType) instanceof Mage_Eav_Model_Entity_Interface)) {
                    $this->addException(Mage::helper('eav')->__('Invalid entity specified'), Varien_Convert_Exception::FATAL);
                }

                $collection = $this->_getCollectionForLoad($entityType);

                if ($hasImage) {
                    $collection
                        ->addAttributeToFilter('image', array('notnull'=>'', 'neq'=>'no_selection'))
                        ->addAttributeToFilter('small_image', array('notnull'=>'', 'neq'=>'no_selection'))
                        ->addAttributeToFilter('thumbnail', array('notnull'=>'', 'neq'=>'no_selection'));
                } else {
                    $collection
                        ->addAttributeToFilter('image', array('no_selection', 'null'))
                        ->addAttributeToFilter('small_image', array('no_selection', 'null'))
                        ->addAttributeToFilter('thumbnail', array('no_selection', 'null'));
                }

                /**
                 * $collection is not a reference, so we need to pass the product IDs
                 * to $this->setData() so that our attribute filters are applied.
                 */
                $entityIds = $collection->getAllIds();
                $this->setData($entityIds);
            } catch (Exception $e) {
                $message = Mage::helper('eav')->__('There was a problem filtering by `hasImage`. Error: %s', $e->getMessage());
                $this->addException($message, Varien_Convert_Exception::FATAL);
            }
        }

        return $this;
    }
}

I'd love to know how I can use $this->setJoinField or parent::setFilter or $this->setJoinAttr to do the same thing, as the parent class does for qty and price. I'll leave my answer unchecked for a few days to see if someone can help me find a better answer.