tags:

views:

116

answers:

3

I am trying to extend Mage_Catalog_Block_Product_View I have it setup in my version of it in my local directory and everything works fine, but I wasn't getting the results that I wanted. I then saw that another class extended that class as well. Which seemed to reset whatever got set from my class. I know that my class is working fine and executing. Its just that there is another class that is a child of the same class I am extending and calling parent::method to the same method I am overriding, that class gets executed after my class and when it does that, it is running the original method that I am overriding and not mine

This is the function

class Mage_Review_Block_Product_View extends Mage_Catalog_Block_Product_View
protected function _prepareLayout()
{
    $this->getLayout()->createBlock('catalog/breadcrumbs');
    $headBlock = $this->getLayout()->getBlock('head');
    if ($headBlock) {
        $title = $this->getProduct()->getMetaTitle();
        if ($title) {
            $headBlock->setTitle($title);
        }
        $keyword = $this->getProduct()->getMetaKeyword();
        $currentCategory = Mage::registry('current_category');
        if ($keyword) {
            $headBlock->setKeywords($keyword);
        } elseif($currentCategory) {
            $headBlock->setKeywords($this->getProduct()->getName());
        }
        $description = $this->getProduct()->getMetaDescription();
        if ($description) {
            $headBlock->setDescription( ($description) );
        } else {
            $headBlock->setDescription( $this->getProduct()->getDescription() );
        }
    }

    return parent::_prepareLayout();
}

I am trying to modify it just a bit with the following, keep in mind I know there is a title prefix and suffix but I needed it only for the product page and also I needed to add text to the description.

class MyCompany_Catalog_Block_Product_View extends Mage_Catalog_Block_Product_View
protected function _prepareLayout()
{
    $storeId = Mage::app()->getStore()->getId();
    $this->getLayout()->createBlock('catalog/breadcrumbs');
    $headBlock = $this->getLayout()->getBlock('head');
    if ($headBlock) {
        $title = $this->getProduct()->getMetaTitle();
        if ($title) {
            if($storeId == 2){
                $title = "Pool Supplies Fast - "  .$title;
            $headBlock->setTitle($title);
        }
            $headBlock->setTitle($title);
        }else{
            $path  = Mage::helper('catalog')->getBreadcrumbPath();

            foreach ($path as $name => $breadcrumb) {
                $title[] = $breadcrumb['label'];
            }
             $newTitle = "Pool Supplies Fast - "  . join($this->getTitleSeparator(), array_reverse($title));
            $headBlock->setTitle($newTitle);
        }
        $keyword = $this->getProduct()->getMetaKeyword();
        $currentCategory = Mage::registry('current_category');
        if ($keyword) {
            $headBlock->setKeywords($keyword);
        } elseif($currentCategory) {
            $headBlock->setKeywords($this->getProduct()->getName());
        }
        $description = $this->getProduct()->getMetaDescription();
        if ($description) {
            if($storeId == 2){
                $description = "Pool Supplies Fast - ". $this->getProduct()->getName() . " - " . $description;
                $headBlock->setDescription( ($description) );
            }else{
              $headBlock->setDescription( ($description) );
            }

        } else {
             if($storeId == 2){
                 $description = "Pool Supplies Fast: ". $this->getProduct()->getName() . " - " . $this->getProduct()->getDescription();
                $headBlock->setDescription( ($description) );
            }else{
              $headBlock->setDescription( $this->getProduct()->getDescription() );
            }

        }
    }

    return Mage_Catalog_Block_Product_Abstract::_prepareLayout();
}

This executs fine but then I notice that the following class Mage_Review_Block_Product_View_List extends which extends Mage_Review_Block_Product_View and that extends Mage_Catalog_Block_Product_View as well. Inside this class they call the _prepareLayout as well and call the parent with parent::_prepareLayout()

class Mage_Review_Block_Product_View_List extends Mage_Review_Block_Product_View
protected function _prepareLayout()
{
    parent::_prepareLayout();

    if ($toolbar = $this->getLayout()->getBlock('product_review_list.toolbar')) {
        $toolbar->setCollection($this->getReviewsCollection());
        $this->setChild('toolbar', $toolbar);
    }

    return $this;
}

So obviously this just calls the same class I am extending and runs the function I am overiding but it doesn't get to my class because it is not in my class hierarchy and since it gets called after my class all the stuff in the parent class override what I have set.

I'm not sure about the best way to extend this type of class and method, there has to be a good way to do this, I keep finding I am running into issues when trying to overide these prepare methods that are derived from the abstract classes, there seems to be so many classes overriding them and calling parent::method.

What is the best way to override these functions?

+1  A: 

are you sure that you have overriden the class correctly ? (I mean putting the <rewrite> tag in config.xml of your module to let magento know you are overriding this class) If yes, please explain in clearer words what you are extending and what you think is not working

matei
Yes everything is setup correctly because I know that it hits my class, I have debugged it and see that it does work. its just that the other class is ran after and calls parent::_prepareLayout() which of course calls Mage_Catalog_Block_Product_View instead of my class.
dan.codes
yes, it's normal, since that class has Mage_Catalog_Block_Product_View as it's parent. I think I understand now what you are saying, but I don't think you can do anything about it, since the class extending mechanism is straightforward (you say class X extends Mage_Catalog_Block_Product_View, not something like: class X extends Mage::getBlock('catalog/product_review') - so you could override that). The only solution is to override the class that calls it's parent and modify it's _prepareLayout too
matei
yeah, I extended that but wasn't sure what to do, I guess put all of the stuff I have in my _prepareLayout in that one as well? since I can't call MyClass::_prepareLayout() since it is not a static function nor is the other class in my class hierarchy. I just have to think that people have extended this class in their extensions somehow as well but I guess they probably had to modify both.
dan.codes
+1  A: 

There are three options here:

  1. Override all the child classes as well, so that they properly descend from your class (or at least call your class in some way).

  2. Place the parent class into the app/code/local/ folder so that Magento finds it rather than the default one. So you'd create the directory app/code/local/Mage/Catalog/Block/Product/ and copy View.php into it. This would be a problem for upgrades, though, as you'd have to merge in any changes that Varien made to the class.

  3. Abandon the rewrites and change it in the template. This may be the best option of all, as you won't have to worry about changes in the _prepareLayout method.

Hope that helps, Joe

Joseph Mastey
1. yeah, this seems like a bit much for the simple thing I am trying to do, so I figured there had to be a better way.2. I was probably just going to do that after messing with this forever.3. I am just not sure how to change it in the template since I am trying to change the meta title and description for only the product page, for the description I have to get the product name.
dan.codes
+1  A: 

Your post is a little unclear, but I think you're running into the Magento limitation of only being able to override classes that are at the bottom of the inheritance chain.

Here's how Magento's override system works. I'm going to use models as an example, but it applies to helpers and blocks as well.

When Magento needs to instantiate an overridable class, it doesn't use the new keyword.

$foo = new FooBar();

instead, a static factory method is called on global Mage object.

$foo = Mage::getModel('foo/bar');

What getModel does is turn the string "foo/bar" into an actual class name. It does this based on a series of rules, one of which is to check all module configuration for any overrides. Once the class name is determined, an object is instantiated.

This works decently, but it means you may only override the instantiation of a class. There's no way to override methods on parent classes, as those methods are inherited via the normal PHP mechanism.

Clarification: So, let's say you have a class Foo which extends Bar

class Bar
{
    public function example()
    {
    }
} 

class Foo extends Bar
{
    public function example()
    {
        return parent::example();
    }
}

and you override class Bar with something like

//magento configured ot use Baz in place of Bar
class Baz
{
}

When someone instantiates a Foo object and calls the example method, parent will resolves to class Bar, even though you've overridden class Bar in the Magento config.

Alan Storm
Thanks Alan, I understand that you have to override the child class that is at the bottom of the chain, so I guess that means instead of extending Mage_Catalog_Block_Product_View I would extend Mage_Review_Block_Product_View_List It just seems weird to extend that one since it is in the reviews. Is there an easy way to see what class is the one you should be extending?when you say "but it means you may only override the instantiation of a class" do you just mean the class that is the final one that calls the class. By the way I have learned most of my Magento development from your articles
dan.codes
Update the post with what I was driving at, which may or may not address what you were after. Glad you've fond the articles useful!
Alan Storm
ahh yeah that is what I thought you meant, so I guess the only option is to extend Foo even if it doesn't make sense to
dan.codes