Caching custom block - magento

im trying to cache a custom block from my module but is not working, is something wrong with my code?
$cacheId = 'my_cache_id';
if (false !== ($data = Mage::app()->getCache()->load($cacheId))) {
$data = unserialize($data);
return $data;
} else {
$collection = Mage::getModel('catalog/product')->getCollection()
->addFieldToFilter('visibility', Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
->addFieldToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
->addMinimalPrice()
->addTaxPercents()
->addStoreFilter()
->addAttributeToSort('entity_id', 'desc');
// CategoryFilter
$collection = $this->categoryFilter($collection);
// getNumProduct
$collection->setPageSize($this->getWidgetCfg('limit'));
Mage::app()->getCache()->save(serialize($collection), $cacheId);
return Mage::app()->getCache()->load($cacheId);
}

your code is a little bit messed up with serialization :)
look into this
// getNumProduct
$collection->setPageSize($this->getWidgetCfg('limit'));
Mage::app()->getCache()->save(serialize($collection), $cacheId);
return Mage::app()->getCache()->load($cacheId);
you are returning serialized object from cache.
simply return $collection, this will even improve initial performance

Related

get page number in object of laravel

i have object given below and i wanted to pagination in this how can i get
$productListArray = array();
$productListObject = ((object)[
"id"=>$productList->id,
"title"=>$productList->title,
"slug"=>$productList->slug,
'categoryName'=>$categoryName[0]->cat_title,
'brand'=>$brandName[0]->brandname,
'minMrp'=>$minMrp,
'maxMrp' =>$maxMrp,
'minSellingPrice' => $minSellingPrice,
'maxSellingPrice' => $maxSellingPrice,
'rating'=>$productList->rating,
'rating_count' => $productList->rating_count,
'image' => $img[0]
])->paginate();
array_push($productListArray, $productListObject);
}
return response()->json($productListArray, 200);
Hi you can get the Current page using laravel paginator Paginator::currentPageResolver
public function index()
{
$currentPage = 3; // You can set this to any page you want to paginate to
// Make sure that you call the static method currentPageResolver()
// before querying users
Paginator::currentPageResolver(function () use ($currentPage) {
return $currentPage;
});
$users = \App\User::paginate(5);
return view('user.index', compact('users'));
}
thanks for your support i found solution,
first add on your header
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
then make an other function
public function paginate($items, $perPage = 5, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
after than call this function where you want in class
$data = $this->paginate($productListArray);
return response()->json($data, 200);
last 2 lines already mentioned in my questions
thanks again

Laravel change pagination data

My Laravel pagination output is like laravel pagination used to be, but I need to change the data array for each object.
My output is:
As you can see, the data object has 2 items, which I need to change.
My code is:
$items = $this->items()
->where('position', '=', null)
->paginate(15);
Which returns the user items with pivot table, but I don't like the way the pivot table is shown in the JSON, so I decided to change the items and organize each item with the pivot before the item.
For this purpose, I tried to use foreach
foreach ($items->data as $item)
{
}
which giving my an error, for a reason I don't know:
Undefined property: Illuminate\Pagination\LengthAwarePaginator::$data"
status_code: 500
Any help?
The paginator's items is a collection. You can grab it and transform the data like so:
$paginator = $this->items()->where('position', '=', null)->paginate(15);
$paginator->getCollection()->transform(function ($value) {
// Your code here
return $value;
});
If you are familiar with tap helper here is the snippet that does exact same.
$paginator = tap($this->items()->where('position', '=', null)->paginate(15),function($paginatedInstance){
return $paginatedInstance->getCollection()->transform(function ($value) {
return $value;
});
});
We can't chain method getCollection to paginator instance because AbstractPaginator will return paginator's underlying collection. so the paginator instance will be transformed to Collection. So fix that we can use tap helper.
If you'd like to keep items paginated:
$itemsPaginated = $this->items()
->paginate(15);
$itemsTransformed = $itemsPaginated
->getCollection()
->map(function($item) {
return [
'id' => $item->id,
];
})->toArray();
$itemsTransformedAndPaginated = new \Illuminate\Pagination\LengthAwarePaginator(
$itemsTransformed,
$itemsPaginated->total(),
$itemsPaginated->perPage(),
$itemsPaginated->currentPage(), [
'path' => \Request::url(),
'query' => [
'page' => $itemsPaginated->currentPage()
]
]
);
There is a setCollection method for such purpose.
$items = Model::paginate(10);
$updatedItems = $items->getCollection();
// data manipulation
// ...
$items->setCollection($updateItems);
From the source code of /Illuminate/Pagination/AbstractPaginator.php
/**
* Set the paginator's underlying collection.
*
* #param \Illuminate\Support\Collection $collection
* #return $this
*/
public function setCollection(Collection $collection)
{
$this->items = $collection;
return $this;
}
Source
I could make shorter way. This returns edited $array instead of simple $paginated. This example modify file names.
This doc was useful for me.
$paginated=$query->paginate(12);
$array=$paginated->toArray();
foreach ($array['data'] as $r=>$record) {
$array['data'][$r]->gif=$array['data'][$r]->gif.".gif";
}
return $array;
Sample Example :
$franchiseData=[ 'id'=>1 ,'name'=>'PAnkaj'];
$models = $bookingsQuery->paginate(10);
$models->setCollection(collect($franchiseData));
return $models;
Note that $models->setCollection(collect($franchiseData)); you have to use collect() else you will get error.
getCollection
is one way to get the items. Another way is to use this
For ex- Assuming, user doesn't have name param and only have first_name and last_name
$userPaginatedData = User::paginate(15);
$users = $userPaginatedData->items();
foreach($users as $user) {
$user->name = $user->first_name . ' ' . $user->last_name;
}
return $userPaginatedData;
Now in the data key, you would see that each user has name param with it.
Laravel 8.9.0 has added the through method to AbstractPaginator.
It transforms each item in the slice of items using a callback, and keeps the items paginated.
$paginator = $this->items()->where('position', '=', null)->paginate(15);
$paginator->through(function ($value) {
// Your code here
return $value;
});
The source code:
/**
* Transform each item in the slice of items using a callback.
*
* #param callable $callback
* #return $this
*/
public function through(callable $callback)
{
$this->items->transform($callback);
return $this;
}
-Laravel 5.4
// example update column "photo"
// from "/path/to/photo.png"
// to "abc.com/path/to/photo.png"
foreach ($items as $item)
{
$path = $item->photo;
// Remove
$item->offsetUnset("photo");
// Set
$item->offsetSet("photo", url($path));
}
Laravel AbstractPaginator has methods setCollection() and getCollection()
<?php
$itemsPaginated = $this->items()->paginate(15);
$itemsPaginated->setCollection(
$itemsPaginated->getCollection()->transform(function ($item) {
// Your code here
return $item;
})
)
This is your paginated items...
$items = $this->items()
->where('position', '=', null)
->paginate(15);
I am using Laravel 8, can simply use each
$items->each(function ($item) {
// your code here
$item->custom_data = calcSomeData(); // sample
});
It does the same as this...
$items->getCollection()->transform(function ($item) {
// your code here
$item->custom_data = calcSomeData(); // sample
});
<?php
$itemsPaginated = $this->items()->paginate(15);
$itemsPaginated = json_encode($itemsPaginated);
foreach ($itemsPaginated->data as $key => $item) {
$results->data[$key]; //Modify
}
$itemsPaginated = json_encode($results);
you have to use below code in your blade
{!! $items->render() !!}
Ignore the pagination in laravel and hit the normal data
foreach ($items as $item)
{
}

Rewriting AutoSuggest (Minisearch) of Magento

I been trying for hours now to successfully rewrite Magento's build-in Autosuggest Function so it displays productnames instead of query history entries. I want nothing fancy, no product pictures and whatnot, just plain product name suggestions.
So to get the productnames, I created under app/code/local/Aw the folder CatalogSearch/Model and there created a file named Query.php. Inside that file I have the following class and rewritten method:
class Aw_CatalogSearch_Model_Query
extends Mage_CatalogSearch_Model_Query {
public function getSuggestCollection() {
$collection = $this->getData('suggest_collection');
if (is_null($collection)) {
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('name', array('like' =>
'%'.$this->getQueryText().'%'))
->addExpressionAttributeToSelect('query_text', '{{name}}', 'name')
->addAttributeToSort('name', 'ASC')
->setPageSize(10)
->addStoreFilter($this->getStoreId());
$this->setData('suggest_collection', $collection);
}
return $collection;
}
};
I created the module xml file in app/etc/modules/ and the module configuration in app/code/local/Aw/CatalogSearch/etc/config.xml
All good so far, the overwritten method getSuggestCollection() is executed.
The problem comes in app/code/core/Mage/CatalogSearch/Block/Autocomplete.php, in the getSuggestData() method.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
When it iterates over the collection, I get a
Call to a member function getQueryText() on a non-object ...
The point I do not understand is that I have defined an alias field named 'query_text' in the collection query inside the getSuggestCollection() method. Even when I used something like getData('query_text') or $item->getQuery_text() to get the data of this field is not working.
I have the strong feeling, that the collection object is not valid as it supposed be within the getSuggestData() method of Mage_CatalogSearch_Block_Autocomplete class.
Can anybody point me out how to solve this issue? Is it not possible as above way to gather suggestions from the products collection and pass these to Autocomplete.php?
This is my first magento project, so please bear with me! I am really lost on this one!
Any hint is greatly apprecitated.
Using Magento 1.7.0.2 for this project.
Well, I found a solution. For anyone who might be interested in this, the problem stated in my question is located in the following lines
$collection = Mage::getModel('catalog/product');
Mage::getSingleton('catalog/product_status')
->addVisibleFilterToCollection($collection);
$collection->getCollection() ... // continue method chaining ...
I changed the code, so that the constructor and methods are chained all together, like this:
$collection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('name') ... // continue method chaining
...
I added the filters for product_status, cataloginventory/stock and catalog/product_visibility with singleton calls right after the collection is available
In that way, everything works as expected.
For anyone else wanting to do something similar, I just rewrote app/code/core/Mage/CatalogSearch/Block/Autocomplete.php to my own module and made the search results query the sku and return product names. Your mileage may vary, however, my sku codes are sensible names rather than random digits so this worked for me.
public function getSuggestData()
{
if (!$this->_suggestData) {
$collection = $this->helper('catalogsearch')->getSuggestCollection();
$query = $this->helper('catalogsearch')->getQueryText();
$counter = 0;
$data = array();
foreach ($collection as $item) {
$_data = array(
'title' => $item->getQueryText(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => $item->getNumResults()
);
if ($item->getQueryText() == $query) {
array_unshift($data, $_data);
}
else {
$data[] = $_data;
}
}
// Get products where the url matches the query in some meaningful way
$products = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToFilter('type_id', 'configurable')
->addAttributeToFilter('sku',array('like'=>'%'.$query.'%'))
->load();
foreach($products as $product) {
$_data = array(
'title' => $product->getName(),
'row_class' => (++$counter)%2?'odd':'even',
'num_of_results' => 1
);
// if ($item->Name() == $query) {
// array_unshift($data, $_data);
// }
// else {
$data[] = $_data;
// }
}
$this->_suggestData = $data;
}
return $this->_suggestData;
}
I did not need to rewrite Mage_CatalogSearch_Model_Query, just the code for the suggestions.

Magento filter product collection by multiple categories

Is there an easy way to filter a product collection by multiple categories? To get all items in any of the listed categories? addCategoryFilter doesn't seem to allow an array.
Is the only way to get the collections for each category of interest separately then merge them?
I understand it used to be possible with something like
addAttributeToFilter('category_ids',array('finset'=>array('1','2')))
or similar, but that this is no longer possible since 1.4.
Note: I am using 1.6, and in case it's of any use, I'm using something like this:
$product = Mage::getModel('catalog/product');
$_productCollection = $product->getCollection()
->addAttributeToSelect('*')
->addAttributeToFilter('status',1)
->addStoreFilter();
Here's a method that doesn't require modifications to core.
It's taken from this post with the addition of the 'group' clause to handle duplicate product records.
$categories = array(7,45,233);
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('*')
->joinField('category_id',
'catalog/category_product',
'category_id',
'product_id=entity_id',
null,
'left')
->addAttributeToFilter('category_id', array('in' => $categories));
$collection->getSelect()->group('e.entity_id');
The way Magento works now, is to get the Store, and on the store, you can get the categories from the storecollection like $oStoreCollection->addCategoryFilter(array('1','2'));
I came across a solution that might help you, found here at:
http://www.magentocommerce.com/boards/&/viewthread/201114/#t329230
The code they use, looks like this:
Override Mage/Catalog/Model/Resource/Eav/Mysql4/Product/Collection, and add the following methods:
public function addCategoriesFilter($categories)
{
$this->_productLimitationFilters['category_ids'] = $categories;
if ($this->getStoreId() == Mage_Core_Model_App::ADMIN_STORE_ID) {
$this->_applyZeroStoreProductLimitations();
} else {
$this->_applyProductLimitations();
}
return $this;
}
protected function _applyProductLimitations()
{
$this->_prepareProductLimitationFilters();
$this->_productLimitationJoinWebsite();
$this->_productLimitationJoinPrice();
$filters = $this->_productLimitationFilters;
// Addition: support for filtering multiple categories.
if (!isset($filters['category_id']) && !isset($filters['category_ids']) && !isset($filters['visibility'])) {
return $this;
}
$conditions = array(
'cat_index.product_id=e.entity_id',
$this->getConnection()->quoteInto('cat_index.store_id=?', $filters['store_id'])
);
if (isset($filters['visibility']) && !isset($filters['store_table'])) {
$conditions[] = $this->getConnection()
->quoteInto('cat_index.visibility IN(?)', $filters['visibility']);
}
// Addition: support for filtering multiple categories.
if (!isset($filters['category_ids'])) {
$conditions[] = $this->getConnection()
->quoteInto('cat_index.category_id=?', $filters['category_id']);
if (isset($filters['category_is_anchor'])) {
$conditions[] = $this->getConnection()
->quoteInto('cat_index.is_parent=?', $filters['category_is_anchor']);
}
} else {
$conditions[] = $this->getConnection()->quoteInto('cat_index.category_id IN(' . implode(',', $filters['category_ids']) . ')', "");
}
$joinCond = join(' AND ', $conditions);
$fromPart = $this->getSelect()->getPart(Zend_Db_Select::FROM);
if (isset($fromPart['cat_index'])) {
$fromPart['cat_index']['joinCondition'] = $joinCond;
$this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
}
else {
$this->getSelect()->join(
array('cat_index' => $this->getTable('catalog/category_product_index')),
$joinCond,
array('cat_index_position' => 'position')
);
}
$this->_productLimitationJoinStore();
Mage::dispatchEvent('catalog_product_collection_apply_limitations_after', array(
'collection' => $this
));
return $this;
}
protected function _applyZeroStoreProductLimitations()
{
$filters = $this->_productLimitationFilters;
// Addition: supprot for filtering multiple categories.
$categoryCondition = null;
if (!isset($filters['category_ids'])) {
$categoryCondition = $this->getConnection()->quoteInto('cat_pro.category_id=?', $filters['category_id']);
} else {
$categoryCondition = $this->getConnection()->quoteInto('cat_pro.category_id IN(' . implode(',', $filters['category_ids']) . ')', "");
}
$conditions = array(
'cat_pro.product_id=e.entity_id',
$categoryCondition
);
$joinCond = join(' AND ', $conditions);
$fromPart = $this->getSelect()->getPart(Zend_Db_Select::FROM);
if (isset($fromPart['cat_pro'])) {
$fromPart['cat_pro']['joinCondition'] = $joinCond;
$this->getSelect()->setPart(Zend_Db_Select::FROM, $fromPart);
}
else {
$this->getSelect()->join(
array('cat_pro' => $this->getTable('catalog/category_product')),
$joinCond,
array('cat_index_position' => 'position')
);
}
return $this;
}
It then gets called like this:
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('*')
->distinct(true) // THIS IS WHAT YOU NEED TO ADD
->addCategoriesFilter($category->getAllChildren(true)); // Make sure you don't forget to retrieve your category here.
HTH
If you want to filter on multiple categories, using AND (so a product must be in categorie A, B and C to show up, you need to have multiple joins:
$products = Mage::getModel('catalog/product')->getCollection()
->joinField('category_id_1', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
->joinField('category_id_2', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
->addAttributeToFilter('category_id_1', array('eq' => 358))
->addAttributeToFilter('category_id_2', array('eq' => 252))
// etc...
;
I managed to resolve this (after much trial and error) with the following code:
$collection = Mage::getModel('catalog/product')->getCollection();
$collection->addAttributeToFilter('status', 1);
$collection->addAttributeToSelect(array('name','sku','price','small_image'));
// Filter by multiple categories
$collection->joinField('category_id','catalog/category_product','category_id','product_id=entity_id',null,'left');
$data_cats = $this->getRequest()->getParam('categories');
// Or $data_cats = array(85,86,87,88);
$filter_cats = array();
foreach ($data_cats as $value_cats) {
$filter_cats[] = array(
'attribute' => 'category_id',
'finset' => $value_cats
);
}
$collection->addAttributeToFilter($filter_cats);
Hope this helps someone ;)
Magento 1.8.0.0;
Flat catalog enabled in admin;
Make sure you've cached the block in which you'll place this;
Don't add this in paid themes ..
The inner join hard-coded here reproduces this:
$collection->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());
without 'cat_index.category_id=2'
$category = Mage::getModel('catalog/category')->load(100);
$allChildsIds = $category->getAllChildren($category);
$visibility = Mage::getModel('catalog/product_visibility');
$collection = Mage::getResourceModel('catalog/product_collection');
$collection = $this->_addProductAttributesAndPrices($collection)
->addStoreFilter()
->setFlag('do_not_use_category_id', true)
->setFlag('disable_root_category_filter', true)
->addAttributeToSort('created_at', 'desc');
$whereCategoryCondition = $collection->getConnection()
->quoteInto('cat_index.category_id IN(?) ', $allChildsIds);
$collection->getSelect()->where($whereCategoryCondition);
$conditions = array();
$conditions[] = "cat_index.product_id = e.entity_id";
$conditions[] = $collection->getConnection()
->quoteInto('cat_index.store_id = ? ', Mage::app()->getStore()->getStoreId());
$conditions[] = $collection->getConnection()
->quoteInto('cat_index.visibility IN(?) ', $visibility->getVisibleInCatalogIds());
$collection->getSelect()->join(
array('cat_index' => $collection->getTable('catalog/category_product_index')),
join(' AND ', $conditions),
array()
);
$collection
->setPageSize(3)
->setCurPage(1);
$collection->load();
Filter Product Collection using multiple category ids
$all_categories = array('3','13','113');
$productCollection = Mage::getModel('catalog/product')->getCollection();
$productCollection->joinField('category_id', 'catalog/category_product', 'category_id',
'product_id = entity_id', null, 'left')
->addAttributeToSelect('*')
->addAttributeToFilter('type_id', array('eq' => 'simple'))
->addAttributeToFilter('category_id', array($all_categories));
foreach($productCollection as $product)
{
echo $product->getId() .$product->getName() . "<br/>";
}
You can remove the condition for product type i.e type_id or modify it as per requirement.
Reference: https://www.fmeextensions.com/blog/get-product-collection-by-category-id-magento-2/
$ids = [1,2,3,4,5,6,7];
$collectionFactory = $objectManager->get('\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory')->create();
$products = $collectionFactory->addAttributeToSelect('*')
->addCategoriesFilter(['in' => $ids]);
foreach ($products as $product) {
echo $product->getId() . "<br />";
echo $product->getName() . "<br />";
echo $product->getProductUrl() . "<br />";
}

How to load products media gallery along with the collection?

Can anybody give me a hint about how to load product's media gallery along with the collection?
I'm getting the collection like this:
$collection = Mage::getModel('catalog/product')->getCollection()
->addStoreFilter($storeId)
->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
foreach ($collection as $product) {
var_dump($product->getMediaGalleryImages());
}
But getMediaGalleryImages() returns null. I know that I can load each product separately with $product = Mage::getModel('catalog/product')->load($product->getId()) but I want to avoid this, because it causing unnecessary workload.
In case anyone’s looking for another approach on this, I found this to work (in just one case so no guarantees!):
Be sure to do $collection->addAttributeToSelect(’image’); first, then when looping through the collection products, do:
$attributes = $product->getTypeInstance(true)->getSetAttributes($product);
$media_gallery = $attributes[’media_gallery’];
$backend = $media_gallery->getBackend();
$backend->afterLoad($product); //this loads the media gallery to the product object
Not sure if all of this is necessary but I’m in a hurry. In my particular case I was trying to get the image url using $product->getImageUrl(); and this approach worked for me.
Hope it helps someone else.
I had to do the same recently, fastest method:
class My_Module_Block_Name extends Mage_Catalog_Block_Product_View_Abstract
{
/** #var null|Mage_Catalog_Model_Resource_Eav_Attribute */
protected static $_mediaGalleryBackend = null;
public function getGalleryImages()
{
$product = $this->getProduct();
$this->_getBackend()->afterLoad($product);
$collection = $product->getMediaGalleryImages();
return $collection;
}
/**
* #return Mage_Catalog_Model_Resource_Eav_Attribute
*/
protected function _getBackend() {
if (self::$_mediaGalleryBackend === null) {
$mediaGallery = Mage::getSingleton('eav/config')
->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'media_gallery');
self::$_mediaGalleryBackend = $mediaGallery->getBackend();
}
return self::$_mediaGalleryBackend;
}
}
try this
$collection = Mage::getModel('catalog/product')->getCollection()
->addStoreFilter($storeId)
->addAttributeToSelect(array('image', 'media_gallery'))
->addAttributeToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
foreach ($collection as $product) {
var_dump($product->getMediaGallery());
}
It can be used directly in loop:
foreach ($collection as $product) {
$product->getResource()->getAttribute('media_gallery')->getBackend()->afterLoad($product);
foreach ($product->getMediaGalleryImages() as $image) {
var_dump($image->debug());
}
}
You are going to have to use:
// Returns the Media Gallery Images
Mage::getModel(’catalog/product’)->load(productid)->getMediaGalleryImages();
Reference: http://www.magentocommerce.com/boards/viewthread/29639/
The secret sauce when working with custom collections involving products is the third parameter of init method... at least it was for me. This way I don't need to load the whole product and run expensive queries.
So, having my custom $product which represents an instance of Mage_Catalog_Model_Product but from my custom collection, I can do:
(string)Mage::helper('catalog/image')->init($product, 'small_image', $product->getImage())
I also needed to add the image attribute to my custom collection, and I did that by adding ->addAttributeToSelect(['image']) to it.
You can also resize your image accordingly:
(string)Mage::helper('catalog/image')->init($product, 'small_image', $product->getImage())->resize($width, $height=null)
Here is a function to add the media gallery to a collection:
// Source: http://www.magentocommerce.com/boards/viewthread/17414/#t141830
public function addMediaGalleryAttributeToCollection(Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $_productCollection) {
$_mediaGalleryAttributeId = Mage::getSingleton('eav/config')->getAttribute('catalog_product', 'media_gallery')->getAttributeId();
$_read = Mage::getSingleton('core/resource')->getConnection('catalog_read');
$_mediaGalleryData = $_read->fetchAll('
SELECT
main.entity_id, `main`.`value_id`, `main`.`value` AS `file`,
`value`.`label`, `value`.`position`, `value`.`disabled`, `default_value`.`label` AS `label_default`,
`default_value`.`position` AS `position_default`,
`default_value`.`disabled` AS `disabled_default`
FROM `catalog_product_entity_media_gallery` AS `main`
LEFT JOIN `catalog_product_entity_media_gallery_value` AS `value`
ON main.value_id=value.value_id AND value.store_id=' . Mage::app()->getStore()->getId() . '
LEFT JOIN `catalog_product_entity_media_gallery_value` AS `default_value`
ON main.value_id=default_value.value_id AND default_value.store_id=0
WHERE (
main.attribute_id = ' . $_read->quote($_mediaGalleryAttributeId) . ')
AND (main.entity_id IN (' . $_read->quote($_productCollection->getAllIds()) . '))
ORDER BY IF(value.position IS NULL, default_value.position, value.position) ASC
');
$_mediaGalleryByProductId = array();
foreach ($_mediaGalleryData as $_galleryImage) {
$k = $_galleryImage['entity_id'];
unset($_galleryImage['entity_id']);
if (!isset($_mediaGalleryByProductId[$k])) {
$_mediaGalleryByProductId[$k] = array();
}
$_mediaGalleryByProductId[$k][] = $_galleryImage;
}
unset($_mediaGalleryData);
foreach ($_productCollection as &$_product) {
$_productId = $_product->getData('entity_id');
if (isset($_mediaGalleryByProductId[$_productId])) {
$_product->setData('media_gallery', array('images' => $_mediaGalleryByProductId[$_productId]));
}
}
unset($_mediaGalleryByProductId);
return $_productCollection;
}
An example of it's usage below:
$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect('*');
$this->addMediaGalleryToArray($products);

Resources