Retrieve multiple products by custom attribute [magento] - magento

I have a custom attribute for the products, and lets say I have 3-4 products that have the same value on that attribute. So, now I want to load these 3 products and store them in an array. Here's what I do:
$all_products = array();
$count = 0;
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ordernumber');
foreach($collection as $product)
{
$all_products[count] = array ('sku' => $product->getSku(), 'qty' => $this->getRequest()->get('qty'), 'size' => $product->getSize());
$count++;
}
return $all_products;
Note: ordernumber HAS a value, I just get it from another place.
Anyway, when I run it - I have no values. When I debug - the debugger terminates at $products[count] = ....
I tried loading a single product just by the custom attribute - Mage::...->loadByAttribute('ordernumber', $ordernumber); and it worked fine.
So, my guess is that I am not doing something correctly with the collection manipulation, or with the array, although, I saw some examples where I got the idea from.
What am I doing wrong?

Try it like this:
$all_products = array();
$count = 0;
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('ordernumber');
//add a filter if needed - uncomment the next 2 lines and adjust the value or $ordernumber
//$ordernumber = '123';
//$addAttributeToFilter('ordernumber', $ordernumber)
foreach($collection as $product)
{
$all_products[$count] = array ('sku' => $product->getSku(), 'qty' => $this->getRequest()->get('qty'), 'size' => $product->getSize());
$count++;
}
return $all_products;

Related

How to get all attributes(visible on frontend) and their corresponding options of a product collection in Magento?

Lets say, these are the attributes color and size. Color has following options red, green and blue and size has following options small,medium and large. Now, assume product collection has two products in it and one product is of red color and has size small and other one is of green color and has size medium. So, I want output like below
Color: red,green
Size: small,medium
I do not want to fetch attribute list collection first and then iterate and match with it attributes of each and every product in collection because that would be very slow and memory consuming.
I debugged how layered navigation works in Magento and based on that I came up with below mentioned solution.
try{
//Get product collection and apply filter to it if any. Here I am applying dummy color filter
$prodCollection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('color',array('in' => array(3,4))); //change this filter ad per your need
$prodCollection
->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
->addMinimalPrice()
->addFinalPrice()
->addTaxPercents()
->addUrlRewrite(Mage::getModel('catalog/layer')->getCurrentCategory()->getId());
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($prodCollection);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($prodCollection);
$setId = 4; //default attribute set id. change this as pre your need. You can also make this an array
//Get catalog attribute collection of some attribute sets.
$attrCollection = Mage::getResourceModel('catalog/product_attribute_collection');
$attrCollection
->setItemObjectClass('catalog/resource_eav_attribute')
->setAttributeSetFilter($setId)
->addStoreLabel(Mage::app()->getStore()->getId())
->setOrder('position', 'ASC');
$attrCollection->addIsFilterableFilter(); //Check if attributes are filterable or not
$attrCollection->load();
$connection = Mage::getSingleton('core/resource')->getConnection('core_read');
$filterResourceModel = Mage::getResourceModel('catalog/layer_filter_attribute');
//Apply filter to product collection, if any
if(1){ //Check if any filters are applied on product collection from query string (?color=4&size=8)
foreach($attrCollection as $attribute){
//For now just for testing purpose, I have hardcoded it to work only for single attribute i.e. color
if($attribute->getAttributeCode() != 'color'){
continue;
}
//I am assuming color filter is applied twice
$filterName = 'color';
$filterId = 92;
$filterVal = array(3,4);
$tableAlias = $attribute->getAttributeCode() . '_fa';
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", $prodCollection->getStoreId()),
$connection->quoteInto("{$tableAlias}.value IN (?)", $filterVal)
);
$prodCollection->getSelect()->join(
array($tableAlias => $filterResourceModel->getMainTable()),
implode(' AND ', $conditions),
array()
);
}
}
//Iterate each attribute one by one. For now just for testing purpose, I have hardcoded it to work only for single attribute i.e. color
foreach($attrCollection as $attribute){
if($attribute->getAttributeCode() != 'color'){
continue;
}
//find attributes options
$options = $attribute->getFrontend()->getSelectOptions();
// clone select from collection with filters
$select = clone $prodCollection->getSelect();
// reset columns, order and limitation conditions
$select->reset(Zend_Db_Select::COLUMNS);
$select->reset(Zend_Db_Select::ORDER);
$select->reset(Zend_Db_Select::LIMIT_COUNT);
$select->reset(Zend_Db_Select::LIMIT_OFFSET);
$tableAlias = sprintf('%s_idx', $attribute->getAttributeCode());
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", Mage::app()->getStore()->getId()), //$filter->getStoreId()
);
$select
->join(
array($tableAlias => $filterResourceModel->getMainTable()),
join(' AND ', $conditions),
array('value', 'count' => new Zend_Db_Expr("COUNT({$tableAlias}.entity_id)")))
->group("{$tableAlias}.value");
$optionsCount = $connection->fetchPairs($select);
$data = array();
foreach ($options as $option) {
if (is_array($option['value'])) {
continue;
}
if (Mage::helper('core/string')->strlen($option['value'])) {
$data[] = array(
'label' => $option['label'],
'value' => $option['value'],
'count' => isset($optionsCount[$option['value']]) ? $optionsCount[$option['value']] : 0,
);
}
}
echo '<pre>'; print_r($data); die('<><>');
}
}catch(Exception $e){
}

Rewriting AutoSuggest (Minisearch) of Magento

I been trying for hours now to successfully rewrite Magento's build-in Autosuggest Function so it displays productnames instead of query history entries. I want nothing fancy, no product pictures and whatnot, just plain product name suggestions.
So to get the productnames, I created under app/code/local/Aw the folder CatalogSearch/Model and there created a file named Query.php. Inside that file I have the following class and rewritten method:
class Aw_CatalogSearch_Model_Query
extends Mage_CatalogSearch_Model_Query {
public function getSuggestCollection() {
$collection = $this->getData('suggest_collection');
if (is_null($collection)) {
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('name', array('like' =>
'%'.$this->getQueryText().'%'))
->addExpressionAttributeToSelect('query_text', '{{name}}', 'name')
->addAttributeToSort('name', 'ASC')
->setPageSize(10)
->addStoreFilter($this->getStoreId());
$this->setData('suggest_collection', $collection);
}
return $collection;
}
};
I created the module xml file in app/etc/modules/ and the module configuration in app/code/local/Aw/CatalogSearch/etc/config.xml
All good so far, the overwritten method getSuggestCollection() is executed.
The problem comes in app/code/core/Mage/CatalogSearch/Block/Autocomplete.php, in the getSuggestData() method.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
When it iterates over the collection, I get a
Call to a member function getQueryText() on a non-object ...
The point I do not understand is that I have defined an alias field named 'query_text' in the collection query inside the getSuggestCollection() method. Even when I used something like getData('query_text') or $item->getQuery_text() to get the data of this field is not working.
I have the strong feeling, that the collection object is not valid as it supposed be within the getSuggestData() method of Mage_CatalogSearch_Block_Autocomplete class.
Can anybody point me out how to solve this issue? Is it not possible as above way to gather suggestions from the products collection and pass these to Autocomplete.php?
This is my first magento project, so please bear with me! I am really lost on this one!
Any hint is greatly apprecitated.
Using Magento 1.7.0.2 for this project.
Well, I found a solution. For anyone who might be interested in this, the problem stated in my question is located in the following lines
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection() ... // continue method chaining ...
I changed the code, so that the constructor and methods are chained all together, like this:
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('name') ... // continue method chaining
...
I added the filters for product_status, cataloginventory/stock and catalog/product_visibility with singleton calls right after the collection is available
In that way, everything works as expected.
For anyone else wanting to do something similar, I just rewrote app/code/core/Mage/CatalogSearch/Block/Autocomplete.php to my own module and made the search results query the sku and return product names. Your mileage may vary, however, my sku codes are sensible names rather than random digits so this worked for me.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
// Get products where the url matches the query in some meaningful way
$products = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('type_id', 'configurable')
->addAttributeToFilter('sku',array('like'=>'%'.$query.'%'))
->load();
foreach($products as $product) {
$_data = array(
'title' => $product->getName(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => 1
);
// if ($item->Name() == $query) {
// array_unshift($data, $_data);
// }
// else {
$data[] = $_data;
// }
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
I did not need to rewrite Mage_CatalogSearch_Model_Query, just the code for the suggestions.

Magento Custom Options showing price in cart/checkout page

Im trying to show each price for custom option in cart-page and checkout-page.
so I have changed this file: app/code/core/Mage/Catalog/Helper/Product/Configuration.php
here at line 75
$options[] = array(
'label' => $option->getTitle(),
'value' => $group->getFormattedOptionValue($itemOption->getValue()),
'print_value' => $group->getPrintableOptionValue($itemOption->getValue()),
'option_id' => $option->getId(),
'option_type' => $option->getType(),
'custom_view' => $group->isCustomizedView(),
//##my changing
'my_price' => $option->getPrice()
);
but this works only with fields, not works when my custom option was a select-box or in radio-buttons.
can someone help, Thanks!
Open up your template file
app/design/frontend/default/theme/template/checkout/cart/item/default.phtml
Find the foreach loop:
<?php foreach ($_options as $_option) : ?>
Within that foreach loop, add this code:
<?php
$optionId = $_option['option_id'];
$product = $_item->getProduct();
$option = $product->getOptionById($optionId);
$itemOption = $_item->getOptionByCode('option_' . $option->getId());
$price = false;
foreach ($option->getValues() as $values) {
if ($values->getId() == $itemOption['value']) {
$price = $values->price;
}
}
if ($price !== false) {
echo Mage::helper('core')->currency($price);
}
?>
Not sure if you've solved your problem yet, but for reference here's what I did..
The custom option prices are only available from the product object, not from the item object (which is what's readily available from the cart/item/default.phtml template). You'll have to find the product id from the item ($_item->getProductId()) then load this product. From there you'll want to load the product options, iterate through the custom option select values (in my case) and pull out the price when the option value ids match from the product and item objects ( http://subesh.com.np/2009/12/custom-options-product-magento/ for more help ).
Hope this helps you get on your way :)

Magento - Get product name for all languages

When reading all magento products for a export extension I've encountered a problem:
when trying to get the name of a product by using getName() on the loaded model you only get the active language name or if that is not set the default name of the product. But I need to get all product names for default, english, german, french, etc.
Does anyone have a solution for this problem or an idea how to solve it?
$model = Mage::getModel('catalog/product');
$collection = $model->getCollection();
foreach ($collection as $product) {
$id = $product->getId();
$model->load($id);
$name = $model->getName(); // gives you only the active language name / default name
}
Since you also want the default store, I'm only aware of one working way:
$aStoreHash = Mage::getModel('core/store')
->getCollection()
->setLoadDefault(true)
->toOptionHash();
$aName = array();
foreach ($aStoreHash as $iStoreId => $sStoreName) {
Mage::app()->setCurrentStore($iStoreId);
$oCollection = Mage::getModel('catalog/product')
->getCollection()
// Uncomment next line for testing if you have thousands of products
// ->addFieldToFilter('entity_id', array('from' => 1, 'to' => 5))
->addAttributeToSelect('name');
foreach ($oCollection as $oProduct) {
$aName[$oProduct->getId()][$iStoreId] = $oProduct->getName();
}
}
var_dump($aName);
If you don't need the default store, you could drop Mage::app()->setCurrentStore($iStoreId); and use ->addStoreFilter($iStoreId) on the collection instead.

Magento - Query for Product Options

I want to write a controller that finds the different options for a given product (eg. Large, Medium, Small, Red, Blue etc...).
Can anyone show me the code I would write into my controller?
Additional details
I'm getting closer, but I still can't figure it out. Here's the code I wrote in my controller
$db = Mage::getModel('catalog/product')->load($productId);
print_r($db->getOptions()); // returns an empty array
echo $db->getHasOptions(); // echos 1
But when I do the print_r() on the second line, the getOptions returns an empty array. The third line echo's the value 1, which means there SHOULD BE options.
Additional Details
I tried clockworkgeek's solution of $db->getProductOptions(), that returned nothing. I tried $db->getProductOptionsCollection(), and got this output
Array
(
[totalRecords] => 0
[items] => Array
(
)
)
What's wrong with my code such that it is not returning the allowable product options?
Instead of getOptions() please try getCustomOptions() or getProductOptionsCollection() or getProductOptionsCollection()->load().
Edit
I tried this on a product I knew had options.
<?php
require 'app/Mage.php';
Mage::app();
$product = Mage::getModel('catalog/product')->load($productId);
foreach ($product->getProductOptions() as $option) {
print_r($option->debug());
}
And got something like this:
Array
(
[option_id] => 37
[product_id] => 8
[type] => multidate
[is_require] => 1
[sku] =>
[image_size_x] => 0
[image_size_y] => 0
[sort_order] => 1
[default_title] => Dates
[title] => Dates
)
However, getOptions() also worked for me so I don't know what's going on.
Post-edit
The confusion was one of semantics. A simple product can have "custom options", they allow creation of a few form fields which are recorded as part of the order. A configurable product uses "associated products" to create a form with conditional fields.
For example you might be selling socks that are large-green, small-green or large-blue - but no small-blue ones. With a simple product you would have a field for large/small and a field for blue/green - which allows the customer to select small-blue and that is wrong.
So to find the component parts of a configurable you might do something like this:
if ($product->isConfigurable()) {
$configurable = $product->getTypeInstance();
$childProducts = $product->getUsedProducts($product);
foreach ($childProducts as $child) {
// You have a $child now
}
}
To find the equivalent of getOptions() you need this:
if ($product->isConfigurable()) {
$configurable = $product->getTypeInstance();
$attributes = $configurable->getConfigurableAttributes($product);
// $attributes is a Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Type_Configurable_Attribute_Collection
foreach ($attributes as $attribute) {
// $attribute is a Mage_Catalog_Model_Product_Type_Configurable_Attribute
print $attribute->getLabel();
}
}
Mage_Catalog_Model_Product_Type_Configurable_Attribute doesn't have much to reveal about itself.
The above solution is perfect and I solved my problem using it. I was
trying to display the colors on the list. Here is my solution
if ($_product->isConfigurable()) {
$configurable = $_product->getTypeInstance();
$childProducts = $configurable->getUsedProducts($_product);
foreach ($childProducts as $child) {
$sku = $child->getSku();
$skuarr = explode('-',$sku);
$col = trim($skuarr[1]);
?>
<span class="colorbar" style="background:<?php echo $col?>;" title="<?php echo $col?>"> </span>
}
}

Resources