3

Consider the example code found in my own block file:

public function getImages()
{
    $images = array();

    $products = Mage::getModel('catalog/product')
        ->getCollection()
        ->addAttributeToSelect('*')
        ->addAttributeToFilter(
            'status',
            array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED)
            );
    $products->getSelect()->order('rand()');
    $products->getSelect()->limit(3);

    foreach ($products as $product) {
        $imageUrl = $product->getImageUrl();
        $image['imageUrl'] = $imageUrl;
        $image['title'] = $product->getName();
        $images[] = $image;
    }
    return $images;
}

In my template file, I have some expected corresponding code:

<div class="images">
    <?php foreach ($this->getImages() as $image): ?>
        <img src="<?php echo $image['imageUrl'] ?>" title="<?php echo $image['title'] ?>">
    <?php endforeach ?>
</div>

This completely works as expected. Three random products are chosen and an image is displayed for each (with the product name as title):

  • Product 1 - Image1 - Title1
  • Product 2 - Image2 - Title2
  • Product 3 - Image3 - Title3

When I attempt to call the image resize helper, however, things get weird. Focus on the foreach ($products as $product) section from the working piece of code above, and see the difference below:

    foreach ($products as $product) {
        // Use the resizer instead of directly calling $product->getImageUrl()
        $imageUrl = $this->helper('catalog/image')->init($product, 'image')->resize(200)->keepFrame(false);
        $image['imageUrl'] = $imageUrl;
        $image['title'] = $product->getName();
        $images[] = $image;
    }

I would expect this to work properly, but instead each product is using the image for the last product listed, but the title remains correct:

  • Product 1 - Image3 - Title1
  • Product 2 - Image3 - Title2
  • Product 3 - Image3 - Title3

It's clear that $image['imageUrl'] is getting assigned correctly in each iteration of the loop, because echo $image['imageUrl'] inside the loop displays the correct URL. Ultimately $image['imageUrl'] is getting reassigned for all iterations to the final value. But why does this occur when using the helper and it doesn't when calling the attribute value directly?

1
  • pff. Casting the return of $this->helper('catalog/image')... to a (string) resolves the issue.
    – pspahn
    Sep 20, 2013 at 3:57

2 Answers 2

11

So as you have discovered the helper init function actually just populates lots of attributes and then returns itself.

If you look at file /app/design/frontend/base/default/template/catalog/product/view/media.phtml line 40 you will see the following:

$_img = '<img src="'.$this->helper('catalog/image')->init($_product, 'image')->resize(265).'" alt="'.$this->htmlEscape($this->getImageLabel()).'" title="'.$this->htmlEscape($this->getImageLabel()).'" />';

I would assume that looking at this it is safe to cast the helper as a string and use the return string as the image path. The helper has a __toString function that will be used when you perform the cast to string.

Edit

When assigning the imageUrl variable to the array it will only assign a reference so you will always get the last one when you come back to this array in the template. If you really want to have the object in the images then try the following.

$image['imageUrl'] = clone $imageUrl;

This will create a separate copy of the object each time. Personally I think that casting it would be the best solution though.

4
  • Yes, I looked through the helper class, and somehow missed the __toString() php magic method. What I am still a bit confused on is why the last image gets used in each iteration. If I happen to only be calling a single product and image, I wouldn't even notice this behavior, it's only during iteration of an array.
    – pspahn
    Sep 20, 2013 at 10:41
  • Yeah that is odd since the init first does a reset. Sep 20, 2013 at 10:43
  • See edit for way of getting different objects into the array. Sep 20, 2013 at 11:53
  • Something I am currently running into is that when resizing, the only way to get a path to the image is by casting to a string - this results in the entire images URL (including base url). There really should be a way to simply get the image's path (ie /media/entity/8/0/8010.jpg).
    – pspahn
    May 19, 2015 at 16:54
-1

You can use this,

Mage::helper('catalog/image')->init($product, 'small_image')->keepFrame(false)->resize('100', '100');

$product => Product collection object,

'small_image' => product image attribute.

1
  • I am not sure you read the question.
    – pspahn
    Sep 20, 2013 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.