Magento add to cart object doesn't contain custom options - magento

I'm using SCP with success, I don't think the problem is there. Basically I've got an observer that looks for the "Add to cart" event and goes from there. Here's my observer method:
public function catalogProductLoadAfter(Varien_Event_Observer $observer)
{
// set the additional options on the product
$action = Mage::app()->getFrontController()->getAction();
if ($action->getFullActionName() == 'checkout_cart_add') {
// assuming you are posting your custom form values in an array called extra_options...
if ($options = $action->getRequest()->getParam('extra_options')) {
$product = $observer->getProduct();
// add to the additional options array
$additionalOptions = array();
if ($additionalOption = $product->getCustomOption('additional_options')) {
$additionalOptions = (array)unserialize($additionalOption->getValue());
}
foreach ($options as $key => $value) {
$additionalOptions[] = array(
'label' => $key,
'value' => $value,
'value' => $value,
);
}
// add the additional options array with the option code additional_options
$observer->getProduct()->addCustomOption('additional_options', serialize($additionalOptions));
}
}
}
All looks well and functions just fine. I've dropped in some Zend_Debug::dump statements at various points and have found where I think the issue is. $product doesn't contain any custom options, or at least doesn't appear to! I've done Zend_Debug::dump($product); and this gives me the following: https://gist.github.com/720a111bc299501726d7 The important thing to see here is that the product object shown is a child product of the configurable. ALL child products have custom options (I just had to set them to get to this stage!).
In the cart page the custom options are displayed correctly, as I've just set them. So why at this midpoint when I do Zend_Debug::dump($product); just before the foreach does the above gist not show any custom options, specifically line 9. My observer fails to do it's job because $additionalOptions ends up being blank, just displays as array {}. As such the foreach doesn't fire and the script falls over. So why are no custom options shown in the gist, yet they ARE there as they show on the product page AND they show after this script executes on the cart page?
To further "prove" this, I'm getting an Invalid argument for foreach() as a result.

Related

Change Magento product's attribute set.

I want to change the attribute set of Magento. I searched through, and everyone suggested to delete the product and re-import it with new attribute set.
I did the same however after importing the data I could not see product reviews and associated blog post with product.
Can anyone tell me is it possible to get product reviews and associated blog post after re-importing the product with new attribute set.
Once set you can't change the attribute set of a product. But it's possible using this module so you don't have to reimport your data
https://marketplace.magento.com/flagbit-magento-changeattributeset.html
It's also possible to change the attribute set directly in the database.
Look up the attribute set ID in table eav_attribute_set
Change the attribute set ID in catalog_product_entity
Of course, be careful when changing data this way.
It is fiddly to do and a bit messy:
Make sure new attribute set is set up
Export the products you want to change
Delete the products that you are changing on the site
Change the attribute set on the downloaded file
Import changed file again
Open each changed product, set their attribute values, save it
Or do what I do, install this great extension from Amasty http://amasty.com/mass-product-actions.html - it makes changing a breeze and gives many more time saving and enhancing options.
Once you delete the product you can't get the old review.
You don't need to delete the product . You can change the attribute set by editing and use.
other wise create a new attribute set and create new product.
Yes. We can change product attribute set programmatically.
I prefer to create massaction in catalog product grid to multiselect product and then select massaction for the products.
Creating massaction in grid.php
$sets = Mage::getResourceModel('eav/entity_attribute_set_collection')
->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId())
->load()
->toOptionHash();
$this->getMassactionBlock()->addItem('changeattributeset', array(
'label'=> Mage::helper('catalog')->__('Change attribute set'),
'url' => $block->getUrl('*/*/changeattributeset', array('_current'=>true)),
'additional' => array(
'visibility' => array(
'name' => 'attribute_set',
'type' => 'select',
'class' => 'required-entry',
'label' => Mage::helper('catalog')->__('Attribute Set'),
'values' => $sets
)
)
));
Creating controller action for change attribute sets of the selected products.
public function changeattributesetAction()
{
$productIds = $this->getRequest()->getParam('product');
$storeId = (int)$this->getRequest()->getParam('store', 0);
if (!is_array($productIds)) {
$this->_getSession()->addError($this->__('Please select product(s)'));
} else {
try {
foreach ($productIds as $productId) {
$product = Mage::getSingleton('catalog/product')
->unsetData()
->setStoreId($storeId)
->load($productId)
->setAttributeSetId($this->getRequest()->getParam('attribute_set'))
->setIsMassupdate(true)
->save();
}
Mage::dispatchEvent('catalog_product_massupdate_after', array('products'=>$productIds));
$this->_getSession()->addSuccess(
$this->__('Total of %d record(s) were successfully updated', count($productIds))
);
}
catch (Exception $e) {
$this->_getSession()->addException($e, $e->getMessage());
}
}
$this->_redirect('adminhtml/catalog_product/index/', array());
}
You can add to your data patch apply function something like this:
public function apply(): self
{
$this->moduleDataSetup->getConnection()->startSetup();
/** #var EavSetup $eavSetup */
$eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
$eavSetup->addAttributeToSet(
Product::ENTITY,
'Default',
'General',
CustomAttributesInterface::ATTRIBUTE_CODE_MANUFACTURER
);
$this->moduleDataSetup->getConnection()->endSetup();
return $this;
}
This changes the manufacturer products attribute to the Default attribute set. (By default this attribute has no attribute set.)
Hope it helps :)

How to find a list of editable attributes in a class - Magento

When creating a product I can use the following via the API:
$newProductData = array(
'name' => (string)$stockItem->STOCK_DESC,
'websites' => array(1,2), // array(1,2,3,...)
'short_description' => (string)$stockItem->STOCK_DESC,
'description' => (string)$stockItem->LONG_DESC,
'status' => 1,
'weight' => $stockItem->WEIGHT,
'tax_class_id' => 1,
'categories' => array(3108),
'price' => $stockItem->SELL_PRICE
);
$my_set_id = 9; // Use whatever set_id you want here
$type = 'simple';
$mc = new Mage_Catalog_Model_Product_Api();
$mc->create($type, $my_set_id, $stockItem->STOCK_CODE, $newProductData);
When I look into the $mc->create call I see that it does this:
foreach ($product->getTypeInstance(true)->getEditableAttributes($product) as $attribute) {
}
which indicates there is a list of attributes which can be edited against an object.
How do I find these? Is there a specific place this information is found?
Edit: I just did:
Mage::log($product->getTypeInstance(true)->getEditableAttributes($product));
and had a look at the results. It seems all the editable attributes are there which can be found under [attribute_code] => but I would still like a better method of knowing where to look to get this list.
This will depend entirely on the attribute set of the product you're trying to edit, and the configuration of each individual attribute. There's no place in the UI that will list these attributes out for you. Your best bet is to run some custom code for your product
$product = Mage::getModel('catalog/product')->load($product_id);
foreach ($product->getTypeInstance(true)->getEditableAttributes($product) as $code=>$attribute)
{
var_dump($code);
}
Here's how to track this information down. If you jump to the getEditableAttributes method
#File: app/code/core/Mage/Catalog/Model/Product/Type/Abstract.php
public function getEditableAttributes($product = null)
{
$cacheKey = '_cache_editable_attributes';
if (!$this->getProduct($product)->hasData($cacheKey)) {
$editableAttributes = array();
foreach ($this->getSetAttributes($product) as $attributeCode => $attribute) {
if (!is_array($attribute->getApplyTo())
|| count($attribute->getApplyTo())==0
|| in_array($this->getProduct($product)->getTypeId(), $attribute->getApplyTo())) {
$editableAttributes[$attributeCode] = $attribute;
}
}
$this->getProduct($product)->setData($cacheKey, $editableAttributes);
}
return $this->getProduct($product)->getData($cacheKey);
}
You can see that this method gets a list of all the attributes set on a particular product.(i.e. All the attributes that are a member of the product's attribute set). Once it has this list, it goes through each and checks if its apply_to property matches the type id of the current product.
The Apply To attribute is set at
Catalog -> Attributes -> Manage Attributes -> [Pick Attribute]
This form field updates the database table catalog_eav_attribute. If you run the following query you can see examples of this value as is stored
select attribute_id, apply_to from catalog_eav_attribute where apply_to is NOT NULL;
75 simple,configurable,virtual,bundle,downloadable
76 simple,configurable,virtual,bundle,downloadable
77 simple,configurable,virtual,bundle,downloadable
78 simple,configurable,virtual,bundle,downloadable
79 virtual,downloadable
So, get your product's attribute set. Get a list of attributes in that set. Compare the value of the attribute's apply_to field vs. the value of your product's type_id. That will let you build a list of these attributes.

Magento New Cart Attribute

Hi well the problem I am facing seemed to be very simple at first but turned into a real nightmare now.
I was asked to add an attribute (namely point) to all the products (which was done pretty simple using the admin panel) and have its total as a cart attribute which rules can be set upon!?
I am quite positive that cart attributes are defined in:
class Mage_SalesRule_Model_Rule_Condition_Address extends Mage_Rule_Model_Condition_Abstract
{
public function loadAttributeOptions()
{
$attributes = array(
'base_subtotal' => Mage::helper('salesrule')->__('Subtotal'),
'total_qty' => Mage::helper('salesrule')->__('Total Items Quantity'),
'weight' => Mage::helper('salesrule')->__('Total Weight'),
'payment_method' => Mage::helper('salesrule')->__('Payment Method'),
'shipping_method' => Mage::helper('salesrule')->__('Shipping Method'),
'postcode' => Mage::helper('salesrule')->__('Shipping Postcode'),
'region' => Mage::helper('salesrule')->__('Shipping Region'),
'region_id' => Mage::helper('salesrule')->__('Shipping State/Province'),
'country_id' => Mage::helper('salesrule')->__('Shipping Country'),
);
$this->setAttributeOption($attributes);
return $this;
}
<...>
So if I overwrite this model and add an item to that array I will get the attribute shown in rule definition admin panel. It seems that all these attributes has a matching column in sales_flat_quote_address table except for total_qty and payment_method!
Now the problem is what should I do to have my new attribute be calculated and evaluated in rules processing? should I add a column to this table and update its value upon cart changes?
Any insight on how to do this would be of great value thanks.
I finally managed to accomplish the task and just for future reference I explain the procedure here.
The class mentioned in the question (ie: Mage_SalesRule_Model_Rule_Condition_Address) is the key to the problem. I had to rewrite it and for some odd reason I couldn't get what I needed by extending it so my class extended its parent class (ie: Mage_Rule_Model_Condition_Abstract).
As I said I added my attribute to $attributes like this:
'net_score' => Mage::helper('mymodule')->__('Net Score')
I also modified getInputType() method and declared my attribute as numeric
now what does the trick is the validate() method:
public function validate(Varien_Object $object)
{
$address = $object;
if (!$address instanceof Mage_Sales_Model_Quote_Address) {
if ($object->getQuote()->isVirtual()) {
$address = $object->getQuote()->getBillingAddress();
}
else {
$address = $object->getQuote()->getShippingAddress();
}
}
if ('payment_method' == $this->getAttribute() && ! $address->hasPaymentMethod()) {
$address->setPaymentMethod($object->getQuote()->getPayment()->getMethod());
}
return parent::validate($address);
}
as you can see it prepares an instance of Mage_Sales_Model_Quote_Address and sends it to its parent validate method. you can see that this object ($address) does not have payment_method by default so this method creates one and assigns it to it. So I did the same, simply I added the following code before the return:
if ('net_score' == $this->getAttribute() && ! $address->hasNetScore()) {
$address->setNetScore( /*the logic for retrieving the value*/);
}
and now I can set rules upon this attribute.
Hope that these information saves somebody's time in the future.

How to get form_dropdown() show the selected value in Codeigniter?

I am trying to populate a dropdown list from database. In my view file I have the following code
$batch= $query ['batch']; // I pull this data from a separate model
echo form_dropdown('shirts', $options, $batch);
Now the drop down list is populating data fine but the problem is I don't get the value-"$batch" automatically selected when the page loads. Interestingly if I echo $batch, elsewhere in the page it shows the correct data, which means $batch is okay.
Here is my Controller
function update($id){
$this->load->model('mod_studentprofile');
$data['query']= $this->mod_studentprofile->student_get($id);
$data['options']= $this->mod_studentprofile->batchget();
$data['tab'] = "Update Student Information";
$data['main_content']='update_studentprofile';
$this->load->view('includes/template',$data);
}
And here is my model
function batchget() {
$this->db->select('batchname');
$records=$this->db->get('batch');
$data=array();
foreach ($records->result() as $row)
{
$data[$row->batchname] = $row->batchname;
}
return ($data);
}
Would you please kindly help me to solve this problem. I want to have the value- "$batch" automatically selected in the dropdown list when the page loads.
Thanks in Advance.
EDit... my Model for student_get($id)
function student_get($id)
{
$query=$this->db->get_where('student',array('studentid'=>$id));
return $query->row_array();
}
Thanks :)
I think that what's probably happening is that the value in $batch may be matching what's rendering in the dropdown but not the actual key in $options for that particular option which would be the value="" portion of the html.
for example...
// this wouldn't select 'foo' as you may be thinking
$options => array('0' => 'foo', '1' => 'bar');
$batch = 'foo';
echo form_dropdown('shirts', $options, $batch);
// this would select foo
$options => array('foo' => 'foo', 'bar' => 'bar');
$batch = 'foo';
echo form_dropdown('shirts', $options, $batch);
Edit in response to OP's comment:
The batchget() method looks like it returns your $options array in the proper format and your student_get() method is returning a row_array. It appears that in the view you're assigning the value of one of the keys returned by the student_get method to be the selected value stored in $batch which is then passed in as the third argument to form_dropdown().
This all appears to be correct. As long as the value of $batch is indeed one of the array keys that is in $options then form_dropdown() will set one of the dropdown options as having been selected.
Debug stuff.
var_dump() $options, var_dump() $batch, look at the two and see where you went wrong.
The third option must be the value of the key, not the value of the label.
Anthony Jack is probably right.

Why does my data not pass into my view correctly?

I have a model, view and controller not interacting correctly, and I do not know where the error lies.
First, the controller. According to the Code Igniter documentation, I'm passing variables correctly here.
function view() {
$html_head = array( 'title' => 'Estimate Management' );
$estimates = $this->Estimatemodel->get_estimates();
$this->load->view('html_head', $html_head);
$this->load->view('estimates/view', $estimates);
$this->load->view('html_foot');
}
The model (short and sweet):
function get_estimates() {
$query = $this->db->get('estimates')->result();
return $query;
}
And finally the view, just to print the data for initial development purposes:
<? print_r($estimates); ?>
Now it's undefined when I navigate to this page. However, I know that $query is defined, because it works when I run the model code directly in the view.
$estimates = $this->Estimatemodel->get_estimates();
$this->load->view('estimates/view', $estimates);
You're loading the return of $this->Estimatemodel->get_estimates() as the array of view variables. In other words, all the children of $estimates (assuming it can be treated as an array) are available in your view. But not the parent element.
The key here is when loading a view the second parameter needs to be an array of values, not just a single value.
$this->load->view('estimates/view', array('estimates' => $estimates));
That should get the result you're looking for, in fact, you're already doing that for the html header view. Even though that view only has one variable, it's passed as the single element of an array:
$html_head = array( 'title' => 'Estimate Management' );
$this->load->view('html_head', $html_head);
The documentation shows that the object you pass to the view must be an associative array.
$data = array(
'estimates' => $estimates
);
$this->load->view('estimates/view', $data);
Docs here

Resources