adding a multiple list attribute to product collection filter in magento - magento

I am trying to do an ajax related magento search, and i can't manage to correctly add a multi-select type product attribute to a product collection,
for instance:
$productModel = Mage::getModel('catalog/product'); //getting product model
$productCollection = $productModel->getCollection();
$productCollection->addAttributeToSelect(
Mage::getSingleton('catalog/config')
->getProductAttributes()
);
$productCollection->addAttributeToFilter(
array(
array('attribute'=>'my_attribute_id',
'finset' => Mage::getResourceModel('catalog/product')
->getAttribute('my_attribute_id')
->getSource()
->getOptionId($searched))
);
where $searched is the string in which i save the keyword. Now, let's presume that my_attribute_id is a multi-select product attribute which has one option named as "Red Bull"...if i search after the exact string "red bull", it works, but i would like to work if i search only after "red" or "bull".
Is there a way to get the option id for an attribute, even if the search string is incomplete? Because the problem is here:
Mage::getResourceModel('catalog/product')
->getAttribute('my_attribute_id')
->getSource()
->getOptionId($searched))
this code returns the id of the attribute option only if i search it entirely.Probably the model does a query something like this
"select...where value='$searched'"
Is there a way to get a list of attribute option id's even if the value of the option is not complete?..so to do a query like this
"select...where value like '%$searched%'"
Or is there a better way to retrieve product collection after a multi-select attribute partial value, other then the solution that I am trying?
Many thanks!

Please try this..
$collection = Mage::getModel('catalog/product')->getCollection();
->addAttributeToSelect('*')
->addFieldToFilter(
'my_attribute_id',
array(
'like' => Mage::getResourceModel('catalog/product')
->getAttribute('my_attribute_id')
->getSource()
->getOptionId($searched)
)
);

Related

Laravel: how to filter eloquent data by relationships

I'm building a product catalog in laravel and I would like to filter the products based on their attributes.
I have 2 tables, Products & Attributes. Attributes have a key, value and product_id. For example:
product_id - key - value
12 - brand - BestBrandEver
23 - brand - EvenBetterBrand
Now I would like to be able to filter down my products via a form on the category page which passes query string parameters like "brand=BestBrandEver or brand=EvenBetterBrand" and retrieve only the products from that brand. Eventually I would like to do the same with color, material etc... It's much like Magento's or Woocommerce layered navigation.
I'm stuck for a while now because I don't know how to start building this the right way. Is there someone who could help me with this or is able to point me in the right direction (maybe even with a tutorial or video)?
Thanks in advance!
Assuming a url like this:
/products?filters[brand][]=a&filters[brand][]=b&filters[color][]=a&filters[color][]=b
and so forth...
Use the whereHas method to restrict your products by their attributes:
Product::whereHas('attributes', function ($query) {
foreach (Input::get('filters') as $key => $values) {
$query->orWhere(function($query) use ($key, $values) {
$query->where('key', $key)->whereIn('value', $values);
});
}
});

Add Child SKUs to Magento Fulltext Search Index

I'm not sure why this isn't part of the stock functionality of Magento, but I want customers to be able to search for a configurable product by a child SKU. For some reason, Magento doesn't index the child SKUs.
I found in app/code/core/Mage/CatalogSearch/Model/Resource/Fulltext.php
$dynamicFields = array(
'int' => array_keys($this->_getSearchableAttributes('int')),
'varchar' => array_keys($this->_getSearchableAttributes('varchar')),
'text' => array_keys($this->_getSearchableAttributes('text')),
'decimal' => array_keys($this->_getSearchableAttributes('decimal')),
'datetime' => array_keys($this->_getSearchableAttributes('datetime')),
);
I've tried several variations, without success. SKU is a "static" attribute, accessible through $this->_getSearchableAttributes('static'). I'm fine with getting all static attributes, but it's not working. Depending on what a try I either get no change in results or an error that the static attribute table doesn't exist (which make sense, because static attributes are in the product entity table).
Does anybody have a suggestion to solve this problem?
Online research has found suggestions to add a hidden attribute with these values, but that shouldn't be needed. I would rather solve the problem properly.
So many ways to do this..
However, I will lead with something I believe would be much cleaner rather than screwing around with the actual Fulltext in app/code/core/Mage/CatalogSearch/Model/Resource/Fulltext.php.
The problem is the lines AFTER that snippet you included:
// status and visibility filter
$visibility = $this->_getSearchableAttribute('visibility');
$status = $this->_getSearchableAttribute('status');
$statusVals = Mage::getSingleton('catalog/product_status')->getVisibleStatusIds();
$allowedVisibilityValues = $this->_engine->getAllowedVisibility();
which ultimately leads to:
core/Mage/CatalogSearch/Model/Resource/Fulltext/Engine.php
/**
* Retrieve allowed visibility values for current engine
*
* #return array
*/
public function getAllowedVisibility()
{
return Mage::getSingleton('catalog/product_visibility')->getVisibleInSearchIds();
}
then:
core/Mage/Catalog/Model/Product/Visibility.php
public function getVisibleInSearchIds()
{
return array(self::VISIBILITY_IN_SEARCH, self::VISIBILITY_BOTH);
}
So what you need to do is go to your simple product associated with your configurable and change the visibility to 'Search'.
However, here it is in action now:
However, yes, that doesn't look pretty at all. The next order of business is now modifying the search results so that when it lists a simple product item that's a.) associated to a configurable product b.) visibility ID is explicitly set to Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH, you need to render the item in search results to the actual configurable product parent (and the rest of its details, such as images).
(I'll continue this later. my computer decided to crap out on me, and I lost over 50% of what I was writing. Even the part where we modify the fulltext class! Darn. see you later.)
I've used the method of setting simple product visibility to search. Then instead of displaying the simple product load/display its parent product.
Beside the frontend query in loop performance issues I never found this solution very satisfying. So after another whack at it I found another option.
I'm adding simple product SKUs to the fulltext index for grouped products but the same approach should work for configurable products.
Here is the idea:
Mage_CatalogSearch_Model_Resource_Fulltext->_prepareProductIndex
contains
$typeInstance = $this->_getProductTypeInstance($productData['type_id']);
if ($data = $typeInstance->getSearchableData($product)) {
$index['options'] = $data;
}
So by overriding the getSearchableData method in the product type class you can add data to the fulltext index. For grouped product my updated looked like:
... extends Mage_Catalog_Model_Product_Type_Grouped
{
/**
* all child SKUs to search data
*/
public function getSearchableData($product=null)
{
$searchData = parent::getSearchableData();
$adapter = Mage::getSingleton('core/resource')->getConnection('core_read');
$select = $adapter->select()
->from(
array('p' => Mage::getSingleton('core/resource')->getTableName('catalog/product')),
array('sku')
)
->joinLeft(
array('r' => Mage::getSingleton('core/resource')->getTableName('catalog/product_relation')),
'r.child_id = p.entity_id',
array()
)
->where('r.parent_id = ?', $this->getProduct($product)->getId());
$query = $adapter->query($select);
while ($row = $query->fetch()) {
$searchData[] = $row['sku'];
}
return $searchData;
}
Reindexed search and catalogsearch_fulltext.dataindex should contain the additional data.
There is a solution for this but it is a paid extension (we license it), it is not build in to Magento standard so you cannot search by child attributes and just return the parent configurable/grouped/bundle product.

Magento: where are catalog filter's (url get parameter's) handled in magento? and where is sql request made to fetch the result?

Magento currently handles only one filter parameter per category .
I want the filter to handle more than one parameter's for the same category.
eg, Suppose I choose 2 colors red and black in the filter using a checkbox for ex, and then click submit button (which I have added), then I want the page to display results for product's having color red or black.
For this, I want to know :
Where are GET parameter's for any filtering process handled in magento.
Where is the sql request made to fetch the results of filtering process.
So that I could handle more than one filter parameter's and display the results.
Any help or suggestion would be of great help.
Thanks in advance..
For your example scenario, you are filtering using attribute color having its attribute ID. The resource model is responsible to execute the SQL operations being performed on any attribute selection.
Go to file app/code/core/Mage/Catalog/Model/Resource/Layer/Filter/Attribute.php
public function applyFilterToCollection($filter, $value)
{
$collection = $filter->getLayer()->getProductCollection();
$attribute = $filter->getAttributeModel();
$connection = $this->_getReadAdapter();
$tableAlias = $attribute->getAttributeCode() . '_idx';
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?", $attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", $collection->getStoreId()),
$connection->quoteInto("{$tableAlias}.value = ?", $value)
);
$collection->getSelect()->join(
array($tableAlias => $this->getMainTable()),
implode(' AND ', $conditions),
array()
);
return $this;
}
In the above function, when you print the collection and exit it before return using,
$collection->printlogquery(true);
you will see the SQL query generated to fetch the results of filtering process.
You can modify this resource model in your local and using INNER JOIN change the SQL query to work for multiple attribute values.

list the values of a product attribute set in magento

how do I find the values of a product's attribute set?
For example, there's a product with an Attribute Set called shirts - T, with attributes of Gender, Shirt Size, and Color. Starting with a $_product object, how do I find the values of the attributes, e.g. Mens, Green, Large?
i am able to getting the attribute set value in the following way:
$product = Mage::getModel('catalog/product')->load($productId);
$prodAttributeSet = Mage::getModel('eav/entity_attribute_set')->load($product->getAttributeSetId())->getAttributeSetName();
I want to get all available attribute set values and codes for specific attribute set(i.e shirt - T)
$_product = Mage::getModel('catalog/product')->load($productId);
Now suppose you want to access value of manufacturer of this product, then consider following code.
$manufacturerValue = $_product->getAttributeText('manufacturer');
As you mention in comment for size and color here i can give you one sample code to use.
If it is a select or multiselect attribute, you still need to map the option ID's to option values. That is the case if you are getting a list of integers instead of human readable labels (e.g. for the color or manufacturer attribute).
// specify the select or multiselect attribute code
$attributeCode = 'color';
// build and filter the product collection
$products = Mage::getResourceModel('catalog/product_collection')
->addAttributeToFilter($attributeCode, array('notnull' => true))
->addAttributeToFilter($attributeCode, array('neq' => ''))
->addAttributeToSelect($attributeCode);
$usedAttributeValues = array_unique($products->getColumnValues($attributeCode));
// ---- this is the different part compared to the previous example ----
// fetch the attribute model
$attributeModel = Mage::getSingleton('eav/config')
->getAttribute('catalog_product', $attributeCode);
// map the option id's to option labels
$usedAttributeValues = $attributeModel->getSource()->getOptionText(
implode(',', $usedAttributeValues)
);
Direct DB query example
Depending on where you want to do this, here is an example of fetching the values without using a product collection. It is slightly more efficient.
Only use the following code in resource models, as thats where DB related code belongs.
This is meant as an educational example to show how to work with Magento's EAV tables.
// specify the attribute code
$attributeCode = 'color';
// get attribute model by attribute code, e.g. 'color'
$attributeModel = Mage::getSingleton('eav/config')
->getAttribute('catalog_product', $attributeCode);
// build select to fetch used attribute value id's
$select = Mage::getSingleton('core/resource')
->getConnection('default_read')->select()
->from($attributeModel->getBackend()->getTable(), 'value')
->where('attribute_id=?', $attributeModel->getId())
->distinct();
// read used values from the db
$usedAttributeValues = Mage::getSingleton('core/resource')
->getConnection('default_read')
->fetchCol($select);
// map used id's to the value labels using the source model
if ($attributeModel->usesSource())
{
$usedAttributeValues = $attributeModel->getSource()->getOptionText(
implode(',', $usedAttributeValues)
);
}
If you want all the attributes of an attribute set you can do the following.
$product = Mage::getModel('catalog/product')->load($productId);
$attributes = $eavConfig->getEntityAttributeCodes( Mage_Catalog_Model_Product::ENTITY, $product );
print_r(attributes);

Magento custom options grid

I have an extension for - Advanced custom options.
I would like to display the related options for every products in the order/grid.
This is the code I use:
protected function _prepareCollection()
{
$collection = Mage::getResourceModel('sales/order_grid_collection');
$collection->getSelect()->join
(
'sales_flat_order_item',
'sales_flat_order_item.order_id = main_table.entity_id',
array
(
'price' => new Zend_Db_Expr('group_concat(sales_flat_order_item.price SEPARATOR "<br><br><hr>")'),
'proname' => new Zend_Db_Expr('group_concat(sales_flat_order_item.name SEPARATOR "<br><hr>")'),
'proptions' => new Zend_Db_Expr('group_concat(sales_flat_order_item.product_options SEPARATOR "<br><hr>")'),
)
);
$collection->getSelect()->group('main_table.entity_id');
$this->setCollection($collection);
return Mage_Adminhtml_Block_Widget_Grid::_prepareCollection();
}
The result I get is incomplete array of the product option related to the product.
How can I get the (proptions) lables/title?
Can you add the following line above your return statement and give me the output? I have a feeling if you're getting a partial response, it may be related to the SQL query itself.
Mage::log($collection->getSelect()->__toString());
You might also try giving leftJoin a shot instead of an inner join by using $collection->getSelect()->leftJoin(), depending on the structure of your query.

Resources