Creating programatically a category when Flat mode is enabled in Magento - magento

I want to create programatically a category in my data folder of my module. The Flat categories option is enabled.
When a I try to create a category like so:
$category
->setStoreId(0)
->setName('My category')
->setUrlKey('club-campaigns')
->setPath($rootCategory->getPath())
->setIsActive(1)
->setIsAnchor(1)
->setIncludeInMenu(1)
->addData($data)
->setCustomDesignApply(1)
->save();
I get an error which says that catalog_category_flat doesn't exists. Ok, so I know that flat categories info is kept in catalog_category_flat_store_storenumber table. I looked in the database and I have the following tables:
catalog_category_flat_store_1
catalog_category_flat_store_2
catalog_category_flat_store_3
catalog_category_flat_store_4
catalog_category_flat_store_5
catalog_category_flat_store_6
and I want to create a category for store 6. Good, now if I do like this:
$category
->setStoreId(6)
->setName('My category')
->setUrlKey('club-campaigns')
->setPath($rootCategory->getPath())
->setIsActive(1)
->setIsAnchor(1)
->setIncludeInMenu(1)
->addData($data)
->setCustomDesignApply(1)
->save();
the category is created without errors, and it sets the info in catalog_category_flat_store_6 but if I go to admin>Manage Categories and cant't see my category created.
I think that when I create a category I should set te store id of the admin(0) so I can see it in the admin panel but then I get the error above, and if I create with store 6 I don't see it in the admin. I'm really stuck.
How can I properly create my category programatically without problems?

Create category dynamically:
$category = Mage::getModel('catalog/category');
$category->setStoreId(Mage::app()->getStore()->getId());
$cat['name'] = "Custom Category Name here";
$cat['path'] = "1/2/30"; //parent relationship..
$cat['description'] = "categorie's description";
$cat['is_active'] = 1;
$cat['is_anchor'] = 0; //for layered navigation
$cat['page_layout'] = 'two_columns_left';
$cat['url_key'] = "custom-category"; //url to access this category
$cat['image'] = "custom-category.jpg";
$category->addData($cat);
$category->save();
Then reindex catalog_category_flat dynamically:
$process = Mage::getSingleton('index/indexer')->getProcessByCode('catalog_category_flat');
$process->reindexEverything();

Related

How to programmatically get option id's and values from configurable product in phtml?

I am modifying phtml code were I have access to
$this which happens to be Mage_Checkout_Block_Cart_Item_Renderer_Configurable class
and
$_item = $this->getItem();
$_product = $_item->getProduct();
where product is a configurable product in a cart.
Based on this I need to get a list of option id (swatches) and their values.
For example, to get specific size option id :
$product = $_item->getProduct();
$idStore = $_item->getOrder()->getStoreId();
$sizeSpecificAttributeCode = 'specific_size';
$sizeAttributeOptionId = $product->getResource()
->getAttributeRawValue($product->getId(), $sizeSpecificAttributeCode,$idStore);
from the same logic you can get the swatches or other options

How to assign categories to a new product automatically?

I am new to Magento and not familiar with it. My requirement is to assign a category to new products automatically. How could I do that?
If you have fixed category to assign when new product is saved then it can be done by observer event (like catalog_product_save_after).
When product is saved, in observer you can write code to assign that newly saved product to particular category.
Following is snippet to assign product to category.
$categories = $product->getCategoryIds();
$categories[] = $categoryId;
$product->setCategoryIds($categories);
$product->save();

Magento add new select value/option to products with upgrade script

I want to make a new select attribute option visible in all products.
I have products that each use a select box attribute called "bracket_size". That attribute has three options:
(/admin/catalog_product_attribute/edit/)
Most of the products only have two of these options selected:
(/admin/catalog_product/edit/)
If I select "18mm" in that screen then it shows on the frontend.
I want to create an upgrade script that will set all products to show the "18mm" option.
I had been doing it by selecting all products, fetching them and updating their attribute value:
$options = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'bracket_size')->getSource()->getAllOptions(false);
$option18mmId = $options[0]['value'];
foreach (Mage::getModel('catalog/product')->getCollection() as $product) {
// Get a writable product
$product = Mage::getModel('catalog/product')->load($product->getId());
// All products in these attribute sets should have bracket sizes
$bracketSizeValue = $product->getBracketSize(); // string containing option IDs - something like '645,345'
if (isset($bracketSizeValue)) {
// Get options currently selected for this product
$optionIds = explode(',', $bracketSizeValue);
// Check if the option is already included in this product
if (!in_array($option18mmId, $optionIds)) {
// If not, rebuild the attribute value to add it
array_unshift($optionIds, $option18mmId);
// Add it back to the product
$product->setData('bracket_size', implode(',', $optionIds));
$product->save();
}
}
}
But this doesn't work. It throws an error:
Warning: Invalid argument supplied for foreach() in /.../public/app/code/core/Mage/Eav/Model/Entity/Abstract.php on line 1068
at the $product->save() line.
How can I do this?
If you trying to save products in setup/update script then you need to disable update mode and set current store id first:
$app = Mage::app();
$app->setUpdateMode(false);
$app->setCurrentStore($app::ADMIN_STORE_ID);
Ideally it would be done exactly before saving and then reverted back after saving:
$app->setCurrentStore(null);
$app->setUpdateMode(true);
Then you could also optimise your code my removing loading and saving of each product and doing it on collection items instead.
Loading of collection with desired attribute:
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToSelect('bracket_code');
Saving of changes on collection items:
$collection->save();

How to select from magento EAV tables when flat catalog product data is on

I have this code for selecting best selling products from Magento:
$productCollection = Mage::getResourceModel('reports/product_collection')
->addOrderedQty($startTime, $currentTime)
->addAttributeToSelect('*')
->setStoreId($storeId)
->addStoreFilter($storeId)
->setOrder('ordered_qty', 'desc')
->setPageSize($this->limit());
}
and it works fine, until I set "use flat catalog product" in backend to yes.
Is there any way to tell magento to not use flat tables, and use EAV instead?
Can any one help me with this.
Create a new model class ('mycatalog/product') that extends the original product class but hard code it to use the EAV resource model and EAV resource collection, and then use that model in your query code.
I'd been running my code from a stand alone php file, as soon as i moved my code into an admin module it stopped using the flat_file and went back to eav.
If you look at: Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
There's a method:
public function isEnabledFlat()
{
if (Mage::app()->getStore()->isAdmin()) {
return false;
}
if (!isset($this->_flatEnabled[$this->getStoreId()])) {
$this->_flatEnabled[$this->getStoreId()] = $this->getFlatHelper()
->isEnabled($this->getStoreId());
}
return $this->_flatEnabled[$this->getStoreId()];
}
You could modify this to add an extra condition that returns false based on your own criteria.
BTW, The reports collection mentioned in the first post by Blazo is an extension of this collection.
To expand on Alan's answer:
class Namespace_Module_Model_Category extends Mage_Catalog_Model_Category
{
protected function _construct()
{
$this->_init('catalog/category');
}
}
The above removes the check to see if flat was enabled and only inits the standard eav verson of the catalog/category resource.
And then when you wish to load your model ensuring that you get the eav model regardless of wither the flat data is enabled:
$category = Mage::getModel('namespace_module/category')->load($id)
I have use
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
before
Mage::getModel('catalog/product')->getCollection()
And it start fetching data from eav based system.
This is an old post but I thought one important point was not stated.
1. Once you set flat catalog to on you need to run indexer via cron or via admin/shell so that flat catalog tables get populated.
If you do have many products in your search bypassing flat catalog table will slow down your site and each search code will consume lots of resources.
I found that the easiest solution was to turn off the flat tables and then get the SQL query that magento executes using the ->load(true) parameter
e.g.
$collection = Mage::getModel('catalog/category')->getCollection();
$collection
->setStoreId($store->getId())
->addAttributeToSelect('*')
->addAttributeToFilter(array(array('attribute'=>'ig_unifeed_ids', 'like'=>"%:".$this->getId().":%")))
->load(true);
then turn flat tables back on and replace this code with:
$resource = Mage::getSingleton('core/resource');
$readConnection = $resource->getConnection('core_read');
$query = "SELECT `e`.*, `at_ig_unifeed_ids`.`value` AS `ig_unifeed_ids` FROM `catalog_category_entity` AS `e` INNER JOIN `catalog_category_entity_varchar` AS `at_ig_unifeed_ids` ON (`at_ig_unifeed_ids`.`entity_id` = `e`.`entity_id`) AND (`at_ig_unifeed_ids`.`attribute_id` = '139') AND (`at_ig_unifeed_ids`.`store_id` = 0) WHERE (`e`.`entity_type_id` = '3') AND ((at_ig_unifeed_ids.value LIKE '%:".$this->getId().":%'))";
$collection = $readConnection->fetchAll($query);
From this point on you will probably need to change other code like replacing
$category->getId()
with
$category["entity_id"]
I hope this helps a bit...
NOTE: this is a real solution for the IG_Unifeed module magento bug that disregards category filtering when using flat tables.

Magento: Get product price from another store?

I have multi-store Magento installation, and different product prices are set in different stores. I want to display on one page the actual product price from the current store, and the price from other store (I have its ID), but I'm not sure how to get that info?
The prices are set for each store view for each product, no tier-pricing or special-pricing was used.
If you know the storeId, set in setStoreId :
/**
* call the Magento catalog/product model
* set the current store ID
* load the product
*/
$product = Mage::getModel('catalog/product')
->setStoreId($storeId)
->load($key);
Display in a block :
echo $product->getName();
We can also use print_r to see the values :
print_r($product->getData());
The following code will show current store ID :
$storeId    = Mage::app()->getStore()->getId();
To get all product ID's with each store view :
$product    = Mage::getModel('catalog/product');
$products   = $product->getCollection()->addStoreFilter($storeId)->getData();
If you change the $storeId will show different product.

Resources