How to save a collection for later use in Magento? - magento

I want to write a cronjob in Magento that loads a product collection following certain parameters and saves it somewhere I can use in a cms/page.
My first approach was to use Magento's registry, but that doesn't work, ie a simple
Mage::register('label',$product_collection);
... doesn't work, as it seems "label" is not available in Mage::registry in my PHTML file...
Can someone point me in the right direction? Is this the correct approach? If so, how to make it work; if not, how to do it?
Thanks in advance!

Unfortunately, Mage::register will not get you where you want to go. The Mage registry keys are saved in the memory of the running PHP script, so it is scoped to the page request that is running the PHP code and therefor not shared between cron and your PHTML file.
In order to accomplish what you're looking for, you would need to cache the collection to persistent storage, such as hard-disk or Memcache. You may have to call the load() function specifically before caching, like so:
<?php
// ...
// ... Somewhere in your cron script
$product_collection = Mage::getModel('catalog/product')->getCollection()
->addFieldToFilter('some_field', 'some_value');
$product_collection->load(); // Magento kind of "lazy-loads" its data, so
// without this, you might not save yourself
// from executing MySQL code in the PHTML
// Serialize the data so it can be saved to cache as a string
$cacheData = serialize($product_collection);
$cacheKey = 'some sort of unique cache key';
// Save the serialized collection to the cache (defined in app/etc/local.xml)
Mage::app()->getCacheInstance()->save($cacheData, $cacheKey);
Then, in your PHTML file try:
<?php
// ...
$cacheKey = 'same unique cache key set in the cron script';
// Load the collection from cache
$product_collection = Mage::app()->getCacheInstance()->load($cacheKey);
// I'm not sure if Magento will auto-unserialize your object, so if
// the cache gives us a string, then we will do it ourselves
if ( is_string($product_collection) ) {
$product_collection = unserialize($product_collectoin);
}
// ...
See http://www.magentocommerce.com/boards/viewthread/240836

Related

Using data stored in cache/storage instead of database

I was thinking about using cache/storage to store source for api routes which doesnt update that much. I mean i would like to update stored data every one minute (example) and my routes will use that data as source instead of database as source. It will make less database queries. Im I thinking in good way? How to achieve that in Laravel?
You could setup an instance of memcached which is supported by Laravel. The Laravel caching documentation is a good place to start learning how to setup a cache driver for memcached. Once setup, your logic could look something like this:
if (Cache::has('key')) {
//your key exists in the cache. get it.
$value = Cache::get('key');
//and use it
useMyValue($value);
}
else
{
//the cache does not contain the key you are looking for
//you can get it from the DB and cache it.
//the next time your function runs it will get the value from cache instead
//of reading from the db
$value = Cache::get('key', function () {
return DB::table(...)->get();
});
//and use your value now like normal
useMyValue()
}

Magento 2 cache solution needed

Hi I'm looking for a cache solution that will allow us to see changes we make across our site much quicker. At the moment we have a cache that runs routinely every day at 1am. The issue I have is that if I want to make changes on the site such as catalog price rules, block changes and category updates, I don't see this until the following day.
Ideally I'd see these changes instantly. Thanks in advance for any tips.
Ronnie
To do this you have to programatically clean it and flush the cache
You can do this in magento 2, but you have to do it manually in your code
The way to do this is:
1. Inject these classed into you constructor dependency
private $_cacheTypeList;
private $_cacheFrontendPool;
public function __construct(
...
\Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
\Magento\Framework\App\Cache\Frontend\Pool $cacheFrontendPool
) {
...
$this->_cacheTypeList = $cacheTypeList;
$this->_cacheFrontendPool = $cacheFrontendPool;
}
2. Write this code inside of your class
$types = array('config','layout','block_html','collections','reflection','db_ddl','eav','config_integration','config_integration_api','full_page','translate','config_webservice');
foreach ($types as $type) {
$this->_cacheTypeList->cleanType($type);
}
foreach ($this->_cacheFrontendPool as $cacheFrontend) {
$cacheFrontend->getBackend()->clean();
}
Inside of the $types array you have all the type of cache you want to clean
Also magento 2 has areas so, you have cache tyes and frontend pool cache types as well.
This will refresh all the types you've entered inside you $types array.
Check magento documentation for all cache types that are available in here
to clean only the ones you need, instead of every single one of them

Magento needs a storeview set to update attribute on website scope

It seems like I have to set a store view before I can update an attribute on website scope – is that correct?
My code:
Mage::app('admin');
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
$product = Mage::getModel('catalog/product');
$product->load(123);
$product->setStoreId('1'); // without this line the attribute is not updated
$product->setSomeattribute("abc");
$product->save();
Yes. that's correct. This is for performance reasons on the frontend. Usually you don't save products from frontend. See a detailed explanation of why is this needed.
But you don't need to do that. I's slow and resource consuming. Try to save it like this:
Mage::getSingleton('catalog/product_action')
->updateAttributes(array(123), array('somattribute'=>'abc'), 1);
The first parameter is and array with the product ids.
The second is an array with the attribute codes and values to be updated.
The third is the store id for which the update is done.
This method is faster.

Auto fill information for movie products in Magento

I'm working with Magento CE 1.6 in a project where we need an easy way to fill the movie info in DVDs and Blu-Rays products for a reseller ecommerce. I'm set to use the Rotten Tomatoes API wich seems very adequate for our purposes, but here's the thing: We don't want to have to input every single detail of the movie in the New Product dialog, oppositely, we want to fetch the info automatically using the movie name as hint (the API perfectly supports this). I though that we could achieve this by two means:
Having the administrator to enter only the names of the movies and
create and run periodically a script that fetches the rest of the
info with the API and updates the data directly in the DB. I've been
watching the DB changes when a product is saved and would'nt like to
do that.
Editing the Magento code to make the new product form auto fillable,
maybe with ajax, once a movie name is entered. Zend framework isn't
my strong and seems kind of hard too.
Am I seeing this problem from the rigth angle? Is there maybe another API? Or a Magento extension? Or another ecommerce?!
I would suggest a little different approach. Enhancing the Admin interface is difficult, but possible. Here is an easier way.
Method #1 - Quick and Easy
Create yourself a script that would go through a list of products. You can select them by attribute type, category, or even just select them all! Then, loop through that collection, and for each product, grab the title, query the movie API, and set the product's attributes. Then, save the product, and move to the next one. Something like this:
Note: Be sure to create your custom attributes in the admin and assign them to the attribute set.
<?php
require_once 'app/Mage.php';
umask(0);
Mage::app('default');
function getVideoDataFromAPI($title)
{
// get your data from the API here...
return $data;
}
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToFilter('attribute_set_id', $yourAttributeSetId)
->addAttributeToFilter('year', ''); // <-- Set a field here that will be empty by default, and filled by the API. This is '' because it won't be null.
foreach ( $collection->getAllIds() as $id ) {
$product = Mage::getModel('catalog/product')->load($id);
$videoData = getVideoDataFromAPI($product->getName());
if ( empty($videoData) ) { continue; }
$product->setYear($videoData['year'])
->setRating($videoData['rating'])
->save();
}
?>
Method #2 - Do the above, but in a custom extension
I always like extensions over scripts. They are more secure and more powerful. With an extension you could have an admin list of the products, can filter them how ever you would like, and have a mass action to pull the video data manually. You could also set it up on a cron job to pull regularly.

Codeigniter pre_system hook for DB driven dynamic controller selection - best approach?

Although I can tentatively see a solution to this, I was wondering if there may be a glaringly obvious simpler approach.
My aim is to use the first segment of a given URI to query the DB as to which controller should be run.
I assume I would have to reform the URI with the resultant controller name in segment 1, then allow the system to continue processing as normal (hence a pre_system hook).
Although not essential I would also like to hold a couple of other variables from the same DB request to be used later in the call stack, and assume this would have to be done using global variables?
Any better suggestions would be gladly received.
Thanks.
Should it be of use to anyone else, here is the code to acheive the desired result. This does however not take into account passing additional variables because I can live without them.
function set_controller()
{
include_once APPPATH.'config/database.php'; //Gather the DB connection settings
$link = mysql_connect($db[$active_group]['hostname'], $db[$active_group]['username'], $db[$active_group]['password']) or die('Could not connect to server.' ); //Connect to the DB server
mysql_select_db($db[$active_group]['database'], $link) or die('Could not select database.'); //Select the DB
$URI = explode('/',key($_GET)); //Break apart the URL variable
$query = 'SELECT * FROM theDomainTable WHERE domainName = "'.$URI[1].'"'; //Query the DB with the URI segment
if($results = mysql_fetch_array(mysql_query($query))){ //Only deal with controller requests that exist in the database
$URI[1] = $results['controllerName']; //Replace the controller segment
$_GET = array(implode('/',$URI)=>NULL); //Reconstruct and replace the GET variable
}
mysql_close($link); //Close the DB link
}
I wouldn't use global variables, Id prefer to store it in a library for retrieval later if possible. Global variables are kind of messy in the context of CI.
Although at pre_system Only the benchmark and hooks class have been loaded at this point. This means you're pretty-much stuck with global variables unless you can find a way to select the controller on pre_controller as all the base-classes are loaded and you can put the data somewhere more logical.

Resources