I'm trying to alter a price based on some custom options set. Therefore I'm trying to get the value a customer has entered, not the default values set in the backend. To do this I'm using the event catalog_product_get_final_price used in Mage_Bundle_Model_Product_Price. I have registered the following observer:
public function observer_callback($evt_obs)
{
$event = $evt_obs->getEvent();
$data = $event->getData();
/* #var $collection Mage_Catalog_Model_Resource_Product_Collection */
$collection = $data['collection'];
$items = $collection->getItems();
/* #var $item Mage_Catalog_Model_Product */
foreach ($items as $item) {
if ( $item->getName() == 'Bundel Test2') {
$options = $item->getCustomOptions();
/* #var $option Mage_Catalog_Model_Product_Option */
foreach ($options as $option) {
// Here I'm trying to get the value given by the user/customer
var_dump($option->getData());
}
}
}
return $this;
}
It is a custom option from a bundle type. So the product can't be configurable.
I'm new to magento so I'm probably missing something.
Can anyone help me?
Hope this piece of code can help you:
public function productFinalPrice($observer){
$product = $observer->getEvent()->getProduct();
$productType=$product->getTypeID();
if($productType == 'your_product_type')
{
$option = $product->getCustomOptions();
$searchedOption = null;
//search for your option;
foreach ($product->getOptions() as $o) {
if($o->getTitle()=="your_attribute_title" && $o->getType()=="your_type_of_option(eg. area"){
$optionId = $o->getOptionId();//got your searched optionId
break;
}
}
foreach($option as $key => $o) {
if($key == "option_".$optionId) {
$searchedOption = $o;
//here you get the option object with the values in it
}
}
$articleNumber = $searchedOption->getData('value'); // getthe value of your option
//calculate final price like you need it
$product->setFinalPrice($finalPrice);
}
return $this;
}
best regards
Related
I have a Topics tree which I use as an attribute on a page:
Categories-
-Topic 1
-Topic 2
-Topic 3
How can I get the topics into an array in a block? Which I can then use in a select box? e.g.
$topics = ("Topic 1", "Topic 2", "Topic 3);
echo $form->select('categories', $topics);
And if my select box is on the right most side of the page, it always has the right border missing. If I move it anywhere else, it shows fine. Anyone else have this?
BTW, for those who want to get values from a select box attribute:
use Concrete\Core\Attribute\Key\CollectionKey as CollectionKey;
use Concrete\Attribute\Select\Controller as SelectController;
use Concrete\Core\Attribute\Type as AttributeType;
$ak = CollectionKey::getByHandle('region');
$at = AttributeType::getByHandle('select');
$satc = new SelectController($at);
$satc->setAttributeKey($ak);
$values = $satc->getOptions()->getOptions();
foreach ($values as $key => $value) {
$this->options[$value->getSelectAttributeOptionID()] = $value->getSelectAttributeOptionValue();
}
Thank you.
[SOLVED]
Thanks to Mike, here's a piece of working code:
use Concrete\Core\Tree\Type\Topic as TopicTree;
public $category = array('');
public function view() {
...
$this->requireAsset('core/topics');
$tt = new TopicTree();
$tree = $tt->getByName('My Categories');
$node = $tree->getRootTreeNodeObject();
$node->populateChildren();
if (is_object($node)) {
foreach($node->getChildNodes() as $key => $category) {
if ($category instanceof \Concrete\Core\Tree\Node\Type\Topic) {
$this->category[$category->getTreeNodeDisplayName()] = $category->getTreeNodeDisplayName();
}
}
}
...
}
You could do something like this within your block controller...
private function getTopics($topicTreeName)
{
$this->requireAsset('core/topics');
$tt = new TopicTree();
/** #var Topic $tree */
$tree = $tt->getByName($topicTreeName);
/** #var TopicCategory $node */
$node = $tree->getRootTreeNodeObject();
$node->populateChildren();
$topics = [];
/** #var Concrete/Core/Tree/Node/Type/Topic $topic */
foreach ($node->getChildNodes() as $topic) {
if ($topic instanceof \Concrete\Core\Tree\Node\Type\Topic) {
$topics[] = [
'id' => $topic->getTreeNodeID(),
'name' => $topic->getTreeNodeDisplayName(),
];
}
}
return $topics;
}
This will get you an array of topics and their Id's (I suspect you would want the id for the value of the select option) like this...
[[name=>'Topic 1', id => 1], [name=>'Topic 2', id => 2]..etc.]
...and then within your view function you can set the variable to make it available within the view template...
public function view() {
$topics = $this->getTopics('My topic name');
$this->set('topics', $topics);
}
You could just then iterate over the topics within your template to output the select list.
Hope that helps with how to get the list of topics?
I'm creating Magento attribute options via a script, but I need to then be able to get the new ID and use it straight away in the same script.
At the moment it's not pulling the id through - if I kill the script and re-start it it picks up the created option and returns the ID, but not as part of the same script.
Here is the code I am using:
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
}else{
echo "No Source";
$vattr_id = false;
}
if($vattr_id){
return $vattr_id;
}else{
$attr_model = Mage::getModel('catalog/resource_eav_attribute');
$attr = $attr_model->loadByCode('catalog_product', $key);
$attr_id = $attr->getAttributeId();
$option['attribute_id'] = $attr_id;
$option['value'][$value][0] = $value;
$option['value'][$value][1] = $value;
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($option);
$attr = Mage::getModel('catalog/product')->getResource()->getAttribute($key);
if ($attr->usesSource()) {
$vattr_id = $attr->getSource()->getOptionId($value);
echo "AttrID: $vattr_id";
}
}
Running this (with the required Mage::app() etc), creates the option, you can see it in the Magento back end, but the $vattr_id is NULL. If I reload the script, then it finds the attribute option in that first block as it should.
I guess it's something to do with how Magento is caching the models, but not sure where I need to look to clear these?
function getAttributeOptionId($attributeName, $attributeValue) {
/* #var $attribute Mage_Eav_Model_Entity_Attribute */
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
// checking attribute code
if ($attribute->getId()) {
$source = $attribute->getSource();
$options = $source->getAllOptions();
// looking for existing id
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
// making new option
$addOptionData = array(
"attribute_id" => $attribute->getId(),
"value" => array(array($attributeValue))
);
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$setup->addAttributeOption($addOptionData);
// getting new id
$attribute = Mage::getModel("eav/entity_attribute")->loadByCode("catalog_product", $attributeName);
$source = $attribute->getSource();
$options = $source->getAllOptions();
foreach ($options as $optionValue) {
if ($attributeValue == $optionValue["label"]) {
return $optionValue["value"];
}
}
}
return null;
}
echo getAttributeOptionId("brand", "Intel");
I've created a new attribute (type: dropdown) that is not a required field.
At this moment, every product shows in the frontend "my attribute: n/a".
After save anything in some product, magento write a null value inside catalog_product_entity_int table for this attribute.
But in the frontend the attribute now appear as "my attribute: No" instead of "N/A".
It looks like a bug, since I didn't touch in the attribute while editing the new product.
Is there a way to deal with it or to apply some rule in my phtml?
Actually this is not a bug. It's a feature.
N/A is displayed when there is no record in the table catalog_product_entity_int for that attribute.
When you add an attribute there are no values for that attribute for any product, but as soon as you save a product that has that attribute, a null value is inserted in the table (as you stated). So no value is different from null value.
All the magic happens here Mage_Catalog_Block_Product_View_Attributes::getAdditionalData().
These are the lines that interest you:
if (!$product->hasData($attribute->getAttributeCode())) { // no value in the database
$value = Mage::helper('catalog')->__('N/A');
} elseif ((string)$value == '') { // empty value in the database
$value = Mage::helper('catalog')->__('No');
}
If you want to change anything override this method.
If you change anything you might want to take a look at Mage_Catalog_Block_Product_Compare_List::getProductAttributeValue().
The same system is used for displaying attribute values in the compare products list.
I've ended up to create 2 observers... One that overrides getValue from Mage_Eav_Model_Entity_Attribute_Frontend_Default and other to override getAdditionalData in Mage_Catalog_Block_Product_View_Attributes as follows:
<?php
class Namespace_Module_Model_Entity_Attribute_Frontend_Default extends Mage_Eav_Model_Entity_Attribute_Frontend_Default{
public function getValue(Varien_Object $object)
{
$value = $object->getData($this->getAttribute()->getAttributeCode());
if (in_array($this->getConfigField('input'), array('select','boolean'))) {
$valueOption = $this->getOption($value);
if (!$valueOption) {
$opt = Mage::getModel('eav/entity_attribute_source_boolean');
$options = $opt->getAllOptions();
if ($options && !is_null($value)) { //added !is_null
foreach ($options as $option) {
if ($option['value'] == $value ) {
$valueOption = $option['label'];
}
}
}
}
$value = $valueOption;
} elseif ($this->getConfigField('input') == 'multiselect') {
$value = $this->getOption($value);
if (is_array($value)) {
$value = implode(', ', $value);
}
}
return $value;
}
}
and
<?php
class Namespace_Module_Block_Product_View_Attributes extends Mage_Catalog_Block_Product_View_Attributes
{
public function getAdditionalData(array $excludeAttr = array())
{
$data = array();
$product = $this->getProduct();
$attributes = $product->getAttributes();
foreach ($attributes as $attribute) {
if ($attribute->getIsVisibleOnFront() && !in_array($attribute->getAttributeCode(), $excludeAttr)) {
$value = $attribute->getFrontend()->getValue($product);
if (!$product->hasData($attribute->getAttributeCode()) || (string)$value == '') { //modified
$value = Mage::helper('catalog')->__('N/A');
} elseif ($attribute->getFrontendInput() == 'price' && is_string($value)) {
$value = Mage::app()->getStore()->convertPrice($value, true);
}
if (is_string($value) && strlen($value)) {
$data[$attribute->getAttributeCode()] = array(
'label' => $attribute->getStoreLabel(),
'value' => $value,
'code' => $attribute->getAttributeCode()
);
}
}
}
return $data;
}
}
I am working in a new "Filter by Product" module in Magento, i have a situation where i should retrieve all attributes and their values. I Googled this and found the below code
$product = Mage::getModel('catalog/product');
$attributes = Mage::getResourceModel('eav/entity_attribute_collection')
->setEntityTypeFilter($product->getResource()->getTypeId())
->load();
// ->addFieldToFilter('attribute_code', 'color')
$attribute = $attributes->getFirstItem()->setEntity($product->getResource());
/* #var $attribute Mage_Eav_Model_Entity_Attribute */
$attr = $attribute->getSource()->getAllOptions(true);
foreach ($attr as $att) {
echo " Label : ".$att['label']." Value : ".$att['value']."";
}
but this retrieves only the label and value of last attribute from list of all available attributes.
how to i get all the attributes? what am i doing wrong in this code?
Thanks,
Balan
Try this:
$attributes = Mage::getSingleton('eav/config')
->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getAttributeCollection();
// Localize attribute label (if you need it)
$attributes->addStoreLabel(Mage::app()->getStore()->getId());
// Loop over all attributes
foreach ($attributes as $attr) {
/* #var $attr Mage_Eav_Model_Entity_Attribute */
// get the store label value
$label = $attr->getStoreLabel() ? $attr->getStoreLabel() : $attr->getFrontendLabel();
echo "Attribute: {$label}\n";
// If it is an attribute with predefined values
if ($attr->usesSource()) {
// Get all option values ans labels
$options = $attr->getSource()->getAllOptions();
// Output all option labels and values
foreach ($options as $option)
{
echo " {$option['label']} (Value {$option['value']})\n";
}
}
else
{
// Just for clarification of the debug code
echo " No select or multiselect attribute\n";
}
}
This is the first solution:
$products = Mage::getModel('catalog/product')->getCollection();
foreach($this->products as $product) {
$prod = Mage::getModel('catalog/product')->load($product->getId());
}
If you are using using the data from outside magento, you can use a class I made:
http://blog.alexparadise.com/magento-dbeav-class/
It's beta but that should work in your case.
Or get the concept of the EAV table... and make your own SQL query.
I can get a list of the children categories for a specific category with the following code:
public function displaycats($data, $begin,$end, $catid){
$currentCat = Mage::getModel('catalog/category')->load($data[0]);
$children = explode(",",$currentCat->getChildren());
foreach ($children as $child) {
$cot++;
$subCat = Mage::getModel('catalog/category')->load($child);
if ($cot >= $begin && $cot <= $end){
echo ''.$subCat->getName()."<br>";
}
}
return;
}
The problem is that the list is not ordered the same as Magento has the categories ordered in the admin area. Can anyone help me out?
I like #Joe Constant's answer, but when I tried it, I was having trouble only getting the first level of child categories, even with $recursionLevel set to 0. As a workaround, I wrote this function (place it in (local version of) whichever block you need the sorted child collection):
public function getChildrenCollection($parentId=false, $sort='ASC', $attribute='position')
{
if (empty($parentId) || !is_numeric($parentId)) return false;
$childrenArray = explode(',',Mage::getModel('catalog/category')->load($parentId)->getChildren());
// remove parent id from array in case it gets returned
if ($key = array_search($parentId, $childrenArray)) {
unset($childrenArray[$key]);
}
$collection = Mage::getModel('catalog/category')->getCollection()
->addAttributeToFilter('entity_id', array('in' => $childrenArray))
->addAttributeToSelect('*');
if (!empty($sort)) {
return $collection->setOrder($attribute, $sort);
}
return $collection;
}
Then you can iterate through the collection and do whatever you need like this:
foreach (getChildrenCollection($parentCategoryId) as $child) {
Zend_Debug::dump($child->getData());
}
Hope that helps.
Look at getCategories instead. It has a sorted parameter as well as an option to return as a collection object removing the need to load each category from the database again.
/**
* Retrieve categories
*
* #param integer $parent
* #param integer $recursionLevel
* #param boolean|string $sorted
* #param boolean $asCollection
* #param boolean $toLoad
* #return Varien_Data_Tree_Node_Collection|Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection
*/
public function getCategories($parent, $recursionLevel = 0, $sorted=false, $asCollection=false, $toLoad=true)
`
$helper = Mage::helper('catalog/category');
$_categories = $helper->getStoreCategories('path', true, FALSE);
If you want to display the category in the following format
category 1
--- sub category 1a
------ sub category 1aa
--- sub category 1b
category 2
---sub category 2a
---sub category 2b
foreach($_categories as $category){
$level = $category['level'] - 2;
$pad = str_repeat("---", ($level > 0) ? $level : 0);
echo $pad . ' ' . $cat['name']);
echo '<br/>';
}
return $categories;
I just wrote something like this to get list of categories (by parentId) sorted like in admin:
$subCats = array();
$children = Mage::getModel('catalog/category')->getCategories($parentId, 1, true, true);
foreach ($children as $category)
{
$subCats[$category->getPosition()] = $category->getId();
}
ksort($subCats);