Magento: how to get the attributes that belong to an attribute set? - magento

Having an attribute set, how can I get a list of the attributes it contains (or better yet, just the custom attributes that don't belong to the Default attribute set)?
The attribute set itself can be obtained in several ways, such as:
$entityTypeId = Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId();
$attributeSet = Mage::getResourceModel('eav/entity_attribute_set_collection')->setEntityTypeFilter($entityTypeId)->addFilter('attribute_set_name', 'Default');
Note that I need to use the attribute set, so getting the list of attributes from a product is not the solution I am looking for.

Mage::getModel('catalog/product_attribute_set_api')->items();
Gets the attribute sets themselves.
Mage::getModel('catalog/product_attribute_api')->items($setId);
Gets the attributes inside the attribute sets.

I believe the answer lies in this model
Mage::getModel('catalog/product_attribute_set_api')->items($setId);
The class is Mage_Catalog_Model_Product_Attribute_Api it seems to have two methods. The items() methods seems to do what you ask i.e. "Retrieve attributes from specified attribute set"
I hope that helps :)

The right way:
$attributes = Mage::getResourceModel('catalog/product_attribute_collection')
->setAttributeSetFilter($attributeSetId)
->getItems();
var_dump($attributes);
You can change resources 'catalog/product_attribute_collection' (customer, ...)
And Set ID $attributeSetId

Regarding Attribute Set, there is a good collection of code snippets in the following blog article:
http://www.blog.magepsycho.com/playing-with-attribute-set-in-magento/
Hope you will find them useful.
Thanks

You don't necessarily need to access the API class. There is a more natural approach available. If you have a product:
/** #var Mage_Catalog_Model_Product $product **/
$attributes = $product->getTypeInstance(true)->getSetAttributes($product);
If not:
$attributes = Mage::getModel('catalog/product')->getResource()
->loadAllAttributes()
->getSortedAttributes($attributeSetId);

I've been searching for an answer, I could'nt find it and I solve my problem with these lines;
$attributeSetId = /* set id */;
$attributes = array();
$groups = Mage::getModel('eav/entity_attribute_group')
->getResourceCollection()
->setAttributeSetFilter($attributeSetId)
->setSortOrder()
->load();
foreach ($groups as $node) {
$nodeChildren = Mage::getResourceModel('catalog/product_attribute_collection')
->setAttributeGroupFilter($node->getId())
//->addFieldToFilter('is_user_defined', true) # I was trying to get user defined attributes.
->addVisibleFilter()
->load();
if ($nodeChildren->getSize() > 0) {
foreach ($nodeChildren->getItems() as $child) {
$attr = array(
'id' => $child->getAttributeId(),
'text' => $child->getAttributeCode()
);
$attributes[] = $attr;
}
}
}
var_dump($attributes);

Related

Magento work with cache, can't serialize collection

I'm learning how to use magento cache and I'm a bit stuck trying to serialize a collection.
Actually this is my code:
class Feliu_Featuredcategories_Block_Topcategories extends Mage_Core_Block_Template
{
protected function _construct()
{
$storeId = Mage::app()->getStore()->getId();
$this->addData(array(
'cache_lifetime' => 3600,
'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG),
'cache_key' => 'homepage-most-view-' . $storeId,
));
}
public function setData()
{
$storeId = Mage::app()->getStore()->getId();
$cache = Mage::app()->getCache();
$key = 'homepage-most-view-' . $storeId;
$cached_categories = $cache->load($key);
if (! $cached_categories) {
$categories = Mage::getModel('catalog/category')
->getCollection()
->addAttributeToSelect(array('data', 'name', 'add_to_top_categories'))
->addAttributeToFilter('add_to_top_categories', array('eq' => '1'));
$categories->load();
$cache->save(serialize($categories), $key);
} else {
$categories = unserialize($cached_categories);
}
return $categories;
}
}
At first I tried to $cache->save($categories, $key); directly, but I read that collections can't be saved directly and I got an error that said: 'automatic_serialization must be on' when I tried to set automatic_serialization to true then I received a message saying that it can't be activated for security reasons.
Then I tried to serialize, just as the above code shows, but it did not work neither. It seems that magento protects collections from being serialized because they can be really big.
So finally I tried to urlencode() before serializing serialize(urlencode($categories)) and urldecode(unserialize($categories)) but I got the string "N;" serializing with this aproach and an empty string when unserialize.
I'm using magento 1.9.3 and I followed this documentation and previous questions:
https://www.nicksays.co.uk/developers-guide-magento-cache/
http://inchoo.net/magento/magento-block-caching/
Magento: serialization error on caching Collection
Magento how to cache a productCollection
And some other questions about this, but maybe there is no need to write too much links, I don't want to spam.
Edit: If instead a collection I use an array like
$categories = array('banana', 'apple', 'kiwi', 'strawberry', 'pomelo', 'melon');
then the code seems to work correctly
Finally I solved it, the answer it's easiest than I though at the beginning but I write it here because maybe it will help somebody in the future.
As collections cannot be cached nor serialized, I made an array with the data I need from the collection.
$categories = Mage::getModel('catalog/category')
->getCollection()
->addAttributeToFilter('add_to_top_categories', array('eq' => '1'))
->addAttributeToSelect(array('data', 'name'));
I make the collection adding only the fields I need, and selecting the data I want.
$array = array();
foreach ($categories as $_category)
{
array_push($array, array('url' => $_category->getUrl(), 'name' => $_category->getName()));
}
Now I make an array that holds objects with the data I wanted. Next step is serialize the array I just made and save it on the cache.
$cache->save(serialize($array), $key, array('custom_home_cache'), 60*60);
and retrieve the data is as easy as $cache->load(unserialize($key))

How to unset (remove) a collection element after fetching it?

I have a collection which I want to iterate and modify while I fetch some of its elements. But I could't find a way or method to remove that fetched element.
$selected = [];
foreach ($collection as $key => $value) {
if ($collection->selected == true) {
$selected[] = $value;
unset($value);
}
}
This is just a representation of my question for demonstration.
After #Ohgodwhy advice the forget() function I checked it again and saw that I actually misunderstood the function. It was exactly as I was looking for.
So for working solution I have added $collection->forget($key) inside the if statement.
Below is the working solution of my problem, using #Ohgodwhy's solution:
$selected = [];
foreach ($collection as $key => $value) {
if ($collection->selected == true) {
$selected[] = $value;
$collection->forget($key);
}
}
(this is just a demonstration)
You would want to use ->forget()
$collection->forget($key);
Link to the forget method documentation
Or you can use reject method
$newColection = $collection->reject(function($element) {
return $item->selected != true;
});
or pull method
$selected = [];
foreach ($collection as $key => $item) {
if ($item->selected == true) {
$selected[] = $collection->pull($key);
}
}
Laravel Collection implements the PHP ArrayAccess interface (which is why using foreach is possible in the first place).
If you have the key already you can just use PHP unset.
I prefer this, because it clearly modifies the collection in place, and is easy to remember.
foreach ($collection as $key => $value) {
unset($collection[$key]);
}
I'm not fine with solutions that iterates over a collection and inside the loop manipulating the content of even that collection. This can result in unexpected behaviour.
See also here: https://stackoverflow.com/a/2304578/655224 and in a comment the given link http://php.net/manual/en/control-structures.foreach.php#88578
So, when using foreach it seems to be ok but IMHO the much more readable and simple solution is to filter your collection to a new one.
/**
* Filter all `selected` items
*
* #link https://laravel.com/docs/7.x/collections#method-filter
*/
$selected = $collection->filter(function($value, $key) {
return $value->selected;
})->toArray();
If you know the key which you unset then put directly by comma
separated
unset($attr['placeholder'], $attr['autocomplete']);
You can use methods of Collection like pull, forget, reject etc.
But every Collection method returns an entirely new Collection instance.
Doc link: https://laravel.com/docs/8.x/collections#introduction

Magento add to cart object doesn't contain custom options

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.

assign new attribute to all attribute sets by coding in magento

I created a new attribute ("for example my_attribute"). Magento's store already has many attribute sets (approx 20).
It's a very time consuming process if I manually add the attribute to the sets because my server is very slow.
I want to assign this new attribute("my_attribute") to all attribute sets programmatically.
Can anyone can help me?
Thanks in advance.
It's quite simple. In a custom module setup script:
$installer = Mage::getResourceModel('catalog/setup','default_setup');
$installer->startSetup();
$installer->addAttribute(
'catalog_product',
'your_attribute_code',
array(
'label' => 'Attribute Label',
'group' => 'General', // this will add to all attribute sets in the General group
// ...
)
)
$installer->endSetup();
For other utilities, see Mage_Eav_Model_Entity_Setup.
Here's something quick, dirty, and untested :)
<?php
$attributeId = ID_HERE;
$installer = new Mage_Catalog_Model_Resource_Eav_Mysql4_Setup('core_setup');
$entityType = Mage::getModel('catalog/product')->getResource()->getEntityType();
$collection = Mage::getResourceModel('eav/entity_attribute_set_collection')
->setEntityTypeFilter($entityType->getId());
foreach ($collection as $attributeSet) {
$attributeGroupId = $installer->getDefaultAttributeGroupId('catalog_product', $attributeSet->getId());
$installer->addAttributeToSet('catalog_product', $attributeSet->getId(), $attributeGroupId, $attributeId);
}
$installer = Mage::getResourceModel('catalog/setup','default_setup');
$installer->startSetup();
$attributeCode = 'my_attribute';
$entity = Mage_Catalog_Model_Product::ENTITY;
// create a new attribute if it doesn't exist
$existingAttribute = $installer->getAttribute($entity, $attributeCode);
if (empty($existingAttribute)) {
$installer->addAttribute($entity, $attributeCode, array(<configure your attribute here>));
}
$attributeId = $installer->getAttributeId($entity, $attributeCode);
// add it to all attribute sets' default group
foreach ($installer->getAllAttributeSetIds($entity) as $setId) {
$installer->addAttributeToSet(
$entity,
$setId,
$installer->getDefaultAttributeGroupId($entity, $setId),
$attributeId
);
}
$installer->endSetup();
As Attributes are not assigned with any attribute set then, you can delete that attribute you created and then create required attribute programmatically.
In the Magento wiki's Programmatically Adding Attributes and Attribute Sets Section, It describes createAttribute as the function that will solve your problem because it will create attributes and also assign them to attribute sets.
Hope This Helps!!
Additionally, Mage_Eav_Model_Entity_Setup and Mage_Catalog_Model_Resource_Setup, which extends from the aforementioned class, have all of the methods that you need to create attributes, sets, and groups. They are fairly straightforward, and they will help you understand how you're supposed to do it properly and prevent you from from writing bad or redundant code. I find most of the articles floating around the Internet and even Magento's own wiki entries feature poorly written code.

Outside link for Add to Cart

We want to get an outside link for a Magento-store page, that would add to cart an item that's linked from a PDF link (it's a technical drawing with some parts that can be ordered separately)
I see that Magento uses JavaScript onclick="productAddToCartForm.submit(this)", but it can not be triggered to the specific item like this.
Is there any way this can be solved?
BR-:g
This is the basic url to call:
www.example.com/checkout/cart/add?product=[id]&qty=[qty]
If you want more details on how to do it with options etc. take a look here:
http://www.magentocommerce.com/wiki/4_-_themes_and_template_customization/catalog/adding_a_product_to_the_cart_via_querystring
You can give add to cart url like:
<?php echo $this->helper('checkout/cart')->getAddUrl($_product);?>
You can always loop over your product collection and ask the checkout/cart helper for the url:
$collection = Mage::getResourceModel('catalog/product_collection');
/* #var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection */
//... add filters to collection as appropriate
$cartHelper = Mage::helper('checkout/cart');
/* #var $cartHelper Mage_Checkout_Helper_Cart */
foreach( $collection as $product ){
/* #var $product Mage_Catalog_Model_Product */
$atcUrl = $carthelper->getAddUrl($product);
//... do what you need to with the above value (echo, fwrite, etc);
}
Note that you can also pass in product-type-specific options as a second param.

Resources