Get a list of attribute options from Magento - php

I've been grabbing attribute options from Magento like so:
<?php
if ($attribute->usesSource()) {
$options = $attribute->getSource()->getAllOptions(false);
}
?>
It's been working fine until I tried to get the options for the built in 'color' attribute -- I got the following error:
PHP Fatal error: Call to a member function setAttribute() on a non-object in app/code/core/Mage/Eav/Model/Entity/Attribute/Abstract.php on line 374
It would appear that the getSource() call fails and causes this error. Does anyone know why this happens and how I can get color options out?
Thanks!

It looks like that you initialize attribute by yourself, instead of using Magento attribute initialization process:
Mage::getSingleton('eav/config')
->getAttribute($entityType, $attributeCode)
Because since 1.4.x Magento has separate attribute models for catalog and customers model and definition of default source model for catalog_product now is moved from EAV attribute model (Mage_Eav_Model_Entity_Attribute) to the catalog one (Mage_Catalog_Model_Resource_Eav_Attribute).
As a result, some catalog attributes won't work with the EAV attribute model. Particularly those that use Mage_Eav_Model_Entity_Attribute_Source_Table but don't explicitly define it (color, manufacturer, etc.).
The following code snippet should work perfectly on your installation:
$attribute = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'color');
if ($attribute->usesSource()) {
$options = $attribute->getSource()->getAllOptions(false);
}
By the way Mage_Eav_Model_Config model has a lot of helpful methods, that can be used in your development, so don't hesitate to look into this model.

The above code does not work if the resource_model is empty. The following snippet does the job:
$attribute = Mage::getModel('eav/entity_attribute')->loadByCode(Mage_Catalog_Model_Product::ENTITY, 'YOUR_ATTRIBUTE_CODE');
/** #var $attribute Mage_Eav_Model_Entity_Attribute */
$valuesCollection = Mage::getResourceModel('eav/entity_attribute_option_collection')
->setAttributeFilter($attribute->getId())
->setStoreFilter(0, false);

$attribute = Mage::getModel('eav/config')->getAttribute('customer','cateinterest');
$options = $attribute->getSource()->getAllOptions();

<?php
//Possible color value
$attribute = Mage::getModel('eav/config')->getAttribute('catalog_product', 'color'); //"color" is the attribute_code
$allOptions = $attribute->getSource()->getAllOptions(true, true);
foreach ($allOptions as $instance) {
$id = $instance['value']; //id of the option
$value = $instance['label']; //Label of the option

Sorry for an incomplete answer, but take a look at the database, specifically in the backend_model column. I seem to remember having this same problem until I set this field to match some of the system fields in this respect.

Related

Magento 2 - Visual Merchandiser Smart Categories with multi-select attributes

Why was support for multiselect attributes in Magento 2 explicitly removed from the collection of allowed attributes for the visual merchandisers "Smart Categories"? We had used this in Magento 1 but need a way to get this same functionality back in Magento 2.
This is where the attributes are explicitly filtered out from the collection.
vendor/magento/module-visual-merchandiser/Model/Config/Source/AllowedAttributes.php
I can remove this like so: (obviously I would do this via a plugin to actually implement this feature)
public function toOptionArray()
{
$entityTypeId = $this->type->loadByCode(\Magento\Catalog\Model\Product::ENTITY)->getId();
if ($entityTypeId) {
$collection = $this->attribute->getCollection()
->removeAllFieldsFromSelect()
->addFieldToSelect('attribute_code', 'value')
->addFieldToSelect('frontend_label', 'label')
->addFieldToFilter('entity_type_id', ['eq' = $entityTypeId]);
// removes multi: ->addFieldToFilter('frontend_input', ['neq' => 'multiselect']);
$attributes = $collection->toArray();
if (isset($attributes['items'])) {
$this->options = $attributes['items'];
}
}
return $this->options;
}
However I feel this is only the tip of the ice berg. What display logic is needed to properly parse these attributes and join the corresponding products to the collection?

How to call getItem() & getOptionList()in an Observer.php - Magento

I have an observer (checkout_cart_product_add_after) and would like to get the selected custom options array.
I have found the two elements I require in: app/design/frontend/MY-THEME/default/template/checkout/cart/item/default.phtml
Which are:
1. $_item = $this->getItem();
2. $_options = $this->getOptionList();
I just don't know how to get them in an observer i.e. what else I have to call.
Thanks in advance!!
please go to the following url
http://inchoo.net/magento/updating-options-of-configurable-product-that-is-already-in-the-cart/
thanks
Observers always start returning data from their respective "events".
So in your case you have to first get checkout-quote object in your observer's function code using below line:
$quote = $observer->getEvent()->getQuote();
Then you can get custom options for each item in items collection from the quote like below:
$quoteItems = $quote->getAllItems();
$helper = Mage::helper('catalog/product_configuration');
foreach ($quoteItems as $item) {
$product = $item->getProduct();
$options = $helper->getCustomOptions($item);
//do anything with $options.
}
Try this. hope it helps.
Also have you already referred below links ?
https://magento.stackexchange.com/questions/16804/get-the-object-of-the-whole-quotation-in-observer
https://magento.stackexchange.com/questions/63752/get-products-final-price-with-its-selected-custom-option-on-add-to-cart
https://magento.stackexchange.com/questions/6368/how-to-get-selected-custom-options-on-onepage

Attach simple products to a configurable product programmatically

I am trying to join some existing simple products programmatically to an existing configurable product.
I hardly found any hints / documentation on this. I examined the MAGMI Magento Mass Importer Plugin (in particular the magmi_productimportengine.php-file) with no success.
After that I found this snippet:
function attachProductToConfigurable($childProduct, $configurableProduct)
{
$loader = Mage::getResourceModel('catalog/product_type_configurable')
->load($configurableProduct, $configurableProduct->getId());
$ids = $configurableProduct
->getTypeInstance()
->getUsedProductIds();
$newids = array();
foreach ($ids as $id) {
$newids[$id] = 1;
}
$newids[$childProduct->getId()] = 1;
//$loader->saveProducts( $_configurableProduct->getid(), array_keys( $newids ) );
$loader->saveProducts($configurableProduct, array_keys($newids));
}
But when I am trying to call the function like this:
$sProduct = Mage::getModel('catalog/product')
->loadByAttribute('sku', $v);
$cProduct = Mage::getModel('catalog/product')
->loadByAttribute('sku', $sku);
attachProductToConfigurable($sProduct, $cProduct);
(each simple product SKU gets passed step by step to the configurable product)
Fatal error: Call to a member function getId() on a non-object in ... on line 1018
which is this line from the function itself
$loader = Mage::getResourceModel('catalog/product_type_configurable')
->load($configurableProduct, $configurableProduct
->getId());
Since I do not find anything similar to joining simple SKUs to an existing configurable product, I am stuck looking up what might be wrong upon initializing the function calls, resource models etc..
Any ideas on what to keep an eye on to get this going are highly appreciated.
Give this a try:
Mage::getResourceSingleton('catalog/product_type_configurable')
->saveProducts($mainConfigrableProduct, $simpleProductIds);
Where $mainConfigrableProduct must be an instance of the configurable product, and $simpleProductIds is an array with the ids of the simple products associated to the configurable products.
On a side note, be very careful when doing this. The simple products must be in the same attribute set as the configurable products. Here is what can happen if they are not.

Getting the fields attached to a bundle of an entity in Drupal

I don't want to get any information from the fields, all I want to get are the field machine names attached to a specific bundle (instance of an entity).
I'm looking into entityfieldquery, entity_load, and entity_get_info, and and I'm leaning towards entity_get_info, but now I'm reading that use is deprecated.
function multi_reg_bundle_select() {
$query = entity_get_info('registration');
}
How do I get information from the attached bundle? ('registration['bundlename']')? Ultimately I just want to get the fields attached to a particular bundle. Preferably in an array of strings.
You can find the answer at https://drupal.stackexchange.com/questions/14352/listing-entity-fields
Short answer: use
$fields = field_info_instances();
to get all info about all entity types and bundles, or use
$fields = field_info_instances('node', 'article');
to get only the fields of the node type "article".
The easiest way to get only the field machine names attached to a specific bundle would be this:
$field_names = array_keys(field_info_instances('node', 'article'));
Using the function already mentioned; a disadvantage of field_info_instances() in some circumstances is that it does not provide the field type. The lightest weight function for that in Drupal 7 is field_info_field_map(). It can be put in a helper function like this:
/**
* Helper function to return all fields of one type on one bundle.
*/
function fields_by_type_by_bundle($entity_type, $bundle, $type) {
$chosen_fields = array();
$fields = field_info_field_map();
foreach ($fields as $field => $info) {
if ($info['type'] == $type &&
in_array($entity_type, array_keys($info['bundles'])) &&
in_array($bundle, $info['bundles'][$entity_type]))
{
$chosen_fields[$field] = $field;
}
}
return $chosen_fields;
}
And use it like so, to get all taxonomy fields on the article content type:
$fields = fields_by_type_by_bundle('node', 'article', 'taxonomy_term_reference');
Note that field_info_field_map() gives only the machine name (as the original poster requested), but you'd have to load the field object with field_info_field() to get the field label (human-readable name).
I believe that field_info_bundles() may be what I am looking for. I'll let people know when I've tested it (but still, if you have suggestions, I'm happy to hear them!)
https://api.drupal.org/api/drupal/modules!field!field.info.inc/function/field_info_bundles/7

Magento - Reassign catalog rules after modifying product attributes

I'm in the process of developing an extension for Magento 1.5.1.0, which allows me to add catalog price rules to products which quantity in stock is reduced to zero. I have added an attribute to my attribute-set called auto_discount_active. This attribute is my on/off switch which works as condition for my price rule.
I wrote an Observer that reacts on the events sales_order_place_after and catalog_product_save_before. It's task is to check wether to stock quantity of the current product has been changed and set my custom attribute to on or off.
The method which handles the catalog_product_save_before event works fine. After saving an article in the backend, the price rule becomes (in)active like it should. The code looks like following:
class Company_AutoDiscount_Model_Observer
{
public function updateAutoDiscount($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$product = $event->getProduct();
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
$attributes = $product->getAttributes();
$attribute = $attributes["auto_discount_active"];
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
}
return $this;
}
}
Now I want to do the same thing, if someone places an order in my shop. That for I use the event sales_order_place_after which works so far. But after changing the custom attributes value, the price rules are not updated. My observer method looks like this:
public function updateAutoDiscountAfterOrder($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$order = $event->getOrder();
foreach ($order->getItemsCollection() as $item)
{
$productId = $item->getProductId();
$productIds[] = $productId;
$product = Mage::getModel('catalog/product')->setStoreId($order->getStoreId())->load($productId);
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
$product->save();
}
Mage::getModel('catalogrule/rule')->applyAllRulesToProduct($productId);
}
return $this;
}
After placing an order and saving the bought article manually in the backend without changes, the price rule gets updated. But I have get the update working in my observer method.
What do I have to do to get the catalog price rule being assigned, after changing the custom attribute?
Thx in advance!
Okay, I want to advise you on some fairly major code optimisations.
You can reduce your collection size and remove the conditional logic inside your loop by using:
$order->getItemsCollection()->addFieldToFilter('is_in_stock', 0);
You could also update all the attributes with a much faster method than save(), by using:
Mage::getSingleton('catalog/product_action')
->updateAttributes($order->getItemsCollection()->addFieldToFilter('is_in_stock', 0)->getAllIds(), array('auto_discount_active' => 1), 0);
Also, bear in mind, you'll also need to apply your observer to any product stock level modification, ie. product save, import, credit memo (refund) - so its a fairly expansive area. You would probably be better served rewriting the stock class, as there isn't too many events dispatched that will give you enough scope to cover this.
Finally, to perform the assignation of rules, I would suggest extending the resource model for the rule (Mage/CatalogRule/Model/Mysql4/Rule.php) so that you can pass in your array of product ids (to save it iterating through the entire catalogue).
You could simply extend getRuleProductIds() to take a Mage::registry variable (if set) with your product ids from the collection above. Then after running the code above, you could just execute
Mage::getModel('catalogrule/rule')->load(myruleid)->save();
Which will re-index and apply rules to new products as necessary - for only the products that have changed.
I would imagine this method cutting overheads by an extremely significant amount.

Categories