The question I propose actually has several parts so I will explain with examples and end with two questions who's answers should answer the topic question.
The file / method in question and instructions to repeat the tests.
app\code\core\Mage\Catalog\Model\Product\Type\Configurable.php (Line 494)
public function getProductByAttributes($attributesInfo, $product = null)
- Create a custom attribute such as "Water Type" with the possible values of, "Clear Water, Opaque Water".
- Create a configurable product that uses the previously created attribute.
- Create two associated simple products, each having one of the possible values.
- Get the product id that you create for simplicity purposes and setup a test environment/extension however you please.
Now let's get some information for this product. I'm going to make some assumptions for testing purposes, such as the product being configurable.
//load up our created product.
$product = Mage::getModel('catalog/product')->load($ourProductId);
//get the attributes for the configurable product and dump them in the magento log.
$attributes = Mage::getModel('catalog/product_type_configurable')->getConfigurableAttributesAsArray($product);
//log the attributes for the product to the log so we can see what's available.
Mage::log(print_r($attributes,true));
//you should get a result similar to this
2014-02-25T21:21:25+00:00 DEBUG (7): Array
(
[0] => Array
(
[id] => 204
[label] => Water Type
[use_default] => 0
[position] => 0
[values] => Array
(
[0] => Array
(
[product_super_attribute_id] => 204
[value_index] => 165
[label] => Clear Water
[default_label] => Clear Water
[store_label] => Clear Water
[is_percent] => 0
[pricing_value] =>
[use_default_value] => 1
)
[1] => Array
(
[product_super_attribute_id] => 204
[value_index] => 166
[label] => Opaque Water
[default_label] => Opaque Water
[store_label] => Opaque Water
[is_percent] => 0
[pricing_value] =>
[use_default_value] => 1
)
)
[attribute_id] => 226
[attribute_code] => water_type
[frontend_label] => Water Type
[store_label] => Water Type
)
)
Now, the end result is that we want to get the associated product model by an array of attributes. Looking at the attributes that are available let's manually create an array for the sake of testing and pass it to getProductByAttributes() and see if we can do that.
We want to get the associated product that has the 'Opaque Water' attribute set, so we'll put that into our array and pass it on. According to the comments above the getProductByAttributes() method it requires an array with $attributeId => $attributeValue. This is what I will put into my first array to pass through based on the information I dumped into my log.
$filterAttributes = array(
'226' => 'Opaque Water'
);
$associatedProduct = Mage::getModel('catalog/product_type_configurable')->getProductByAttributes($filterAttributes,$product);
//let's see if it worked
if ($associatedProduct !== NULL)
{
Mage::log('We found the ' . $associatedProduct->getTypeId() . ' associated product, yay');
} else {
Mage::log('No product found, its null, boo');
}
The result you should/will receive is sadly null. Let's do some logging on the method and try to figure out why it's null! Let's count the collection within the getProductByAttributes before it returns anything so that we're sure it's grabbing the associated products, it should return 2 products before the filtering is done.
Add this line of code inside of the getProductByAttributes method in this file, app\code\core\Mage\Catalog\Model\Product\Type\Configurable.php.
//add this directly after the 'getUsedProductCollection' call and before the attributes are added to filter by. This will give us the count of that collection before it filters it.
Mage::log('Product collection count: ' . $productCollection->count());
If done correctly, your log will show some magic just happened. Your product was found and the result from the previous code is no longer null. This brings me to the first question.
Question #1 Why does the count change the fact that the filter previously didn't work?
Now let's remove the $productCollection->count() and test again to verify you still get null. This should definitely be the case. Let's now change the $filterAttributes array to use the value_index instead of the name of the value.
//change from 'Opaque Water' to '165', the value_index from the attributes array we dumped.
$filterAttributes = array(
'226' => '165'
);
Run it all again and get the outcome. It works fine, without needing to add in the $productCollection->count().
Question #2 Why does using value_index work without needing to force the collection to load prior to adding the filters?
Possible Answer / Guess
I have some theories of why, but I don't know if they are correct or not. I will provide them either way.
Theory #1 The attribute value name isn't available until the collection is loaded, which is why loading it with the count makes it work with the filter is applied. This doesn't make sense to me though because wouldn't the filter use those attributes during the select statements in the database and get the same result without needing for the collection to be force loaded?
Theory #2 Bad variable naming and comments. Whether or not it works after force loading the collection with count, the $attributeValue should be something other than what it implies such as value_index that works. This implies that what I passed first 'Opaque Water' is an actual value. I've also considered that it's not technically a value and that because we're dealing with a select, value_index is actually the value regardless of what it's called when you dump the attributes.