I am trying to build a page in Magento that essentially lists all products in a specific category WITH layered navigation (filters on the left side in my case), but the list must be randomly generated once a day.
I have tried to use "product_list_random", but it seems to ignore CategoryIDs settings.
Investigating further, I located Random.php and the problem is that protected function _getProductCollection in Random.php simply starts from a full product collection, whereas in List.php, it has some logic to fetch the current category.
Now I am battling to adapt the code from List.php to Random.php, but no success...
Here is my code so far:
$layer = $this->getLayer();
/* @var $layer Mage_Catalog_Model_Layer */
$origCategory = null;
if ($this->getCategoryId()) {
$category = Mage::getModel('catalog/category')->load($this->getCategoryId());
if ($category->getId()) {
$origCategory = $layer->getCurrentCategory();
$layer->setCurrentCategory($category);
}
}
//$this->_productCollection = $layer->getProductCollection();
$this->_productCollection = $layer->getSelect()->order('rand()');
$this->prepareSortableFieldsByCategory($layer->getCurrentCategory());
if ($origCategory) {
$layer->setCurrentCategory($origCategory);
}
Now it seems that you can't "rand" Magento's layer model, but I am a bit lost here. Any ideas as how to finish this? I can sense I am very close, but am missing something... :(
Thanks in advance!
UPDATE 2
Ok. I think I got what's happening. I rewrote the code in a "more optimized/rational" way and still get the paging problem.
I xdebugged part of the rendering process and what seems to be happening is that Toolbar.phtml/php is called PRIOR TO Random.php. The reason for that is two-fold: (1) My Layout actually states toolbar as a child to Random, so it should be called first; and (2) It HAS TO be called first, as the Toolbar needs to know how many elements it will be paging.
Because of this, once I call setCollection in my code, all the paging parameters are already there, so paging breaks... :( That's my theory.
The only workaround I can think of is to reset all toolbar parameters after my collection loads, which (1) seems irrational (there's got to be a better way!) and (2) I'm not sure how to pull it out... :( :(
The current code follows... As usual, any pointers would be much appreciated!
protected function _getProductCollection()
{
//xdebug_start_trace('/Library/WebServer/talcha/var/log/random-trace.txt');
/* get ready to build collection */
$collection=Mage::getResourceModel('catalog/product_collection');
$genlayer=Mage::getModel('catalog/layer');
$genlayer->prepareProductCollection($collection);
$collection->addAttributeToFilter('status',1); //only enabled product
$collection->addAttributeToFilter('visibility',4); //only 'catalog,search' products
$collection->addStoreFilter();
/* Find out where I am */
$newrandom=false; // flag to check if random collection was generated
$interna=false;
$currentUrl = $this->helper('core/url')->getCurrentUrl();
Mage::log("URL:".$currentUrl,null,"paulo.log");
if (strpos($currentUrl,"chas")!==false) { // estou em CHAS
$interna=true;
}
/* if I am where I need to be, then check whether I need to update the collection */
if ($interna) {
$now=time();
/* fetch collection file name and generated time */
if (strpos($currentUrl,"?")===false) {
$name=substr($currentUrl,strpos($currentUrl,"index.php")+10);
} else {
$name=substr($currentUrl,strpos($currentUrl,"index.php")+10,strpos($currentUrl,"?")-strlen($currentUrl));
}
if ($name=="chas2") { $name="chas"; }
Mage::log("Nome:".$name,null,"paulo.log");
$dir=Mage::getBaseDir('tmp');
$dh=opendir($dir);
while (($file=readdir($dh))!=false) {
Mage::log("Arq.:".$file,null,"paulo.log");
if (strpos($file,$name)!==false) {
$epoch=substr($file,strpos($file,"-")+1);
$fname=$file;
Mage::log("Hora:".$epoch,null,"paulo.log");
break;
}
}
/* tests whether elapsed time between now and last update is longer that "x" seconds */
/* if true, generates new random collection, serialize it and flag it */
/* if false, just picks up last generated collection from file */
if (($now-$epoch) > 3600) { //set 1 hour
$collection->addCategoryFilter(Mage::getModel('catalog/category')->load($this->get_cur_category()));
$collection->getSelect()->order('rand()');
file_put_contents($dir."/".$name."-".$now,serialize($collection));
unlink($dir."/".$fname);
$newrandom=true;
Mage::log("Fiz shuffle!",null,"paulo.log");
Mage::log("Count:".$collection->count(),null,"paulo.log");
} else {
$collection=unserialize(file_get_contents($dir."/".$fname));
}
} // close if($interna)
/* build the final collection. If we are using the generated collection, we need
to adjust pagination according to request parameters.
If we are filtering, then we set proper filters and load the ordinary collection
(no random stuff when filtering through) */
if (is_null($this->_productCollection)) {
$layer=$this->getLayer();
foreach($this->getRequest()->getParams() as $key=>$value) {
Mage::log("Random:".$key."=>".$value,null,"paulo.log");
switch ($key) {
case "p":
$collection->setPageSize($this->get_prod_count())->setCurPage($value);
break;
case "cat":
$collection->addCategoryFilter(Mage::getModel('catalog/category')->load($value));
break;
case "price":
list($range,$step)=explode(",",$value);
$gt_value=($range-1)*$step;
$lt_value=$range*$step;
$collection->addAttributetoFilter($key,array('gt'=>$gt_value));
$collection->addAttributetoFilter($key,array('lteq'=>$lt_value));
break;
case "limit":
$collection->setPageSize($value)->setCurPage(1);
break;
case "page_id":
case "dir":
case "order":
case "mode":
break;
default:
$collection->addAttributeToFilter($key,$value); //filters
}
}
/* if we are filtering, then the collection wasn't loaded yet */
if (!$interna) {
$collection->load();
}
}
$this->setCollection($collection);
$this->_productCollection=$collection;
return $this->_productCollection;
}