3

I found it is possible to do a rewrite on a core class that does not actually exist....

Usage case example:

I am creating a reCaptcha module that integrates google recaptcha into magento's core captcha system. In the core captcha you have the ability to state a 'type', as can be seen in the config.xml of Mage_Captcha

<default>
......
<admin>
            <captcha>
                <type>zend</type>   <<<<<<<<<<<<<<< specify a captcha type (model)
                <enable>0</enable>
                <font>linlibertine</font>
                <mode>after_fail</mode>
                <forms>backend_forgotpassword</forms>
                <failed_attempts_login>3</failed_attempts_login>
                <failed_attempts_ip>1000</failed_attempts_ip>
                <timeout>7</timeout>
                <length>4-5</length>
                <symbols>ABCDEFGHJKMnpqrstuvwxyz23456789</symbols>
                <case_sensitive>0</case_sensitive>
                <always_for>
                    <backend_forgotpassword>1</backend_forgotpassword>
                </always_for>
            </captcha>
        </admin>
......
</default>

so in my module I extend the core functionality and added a new type called 'recaptcha'

However, the developer of that core module kinda locked the model location down to exist within the Mage_Captcha namespace, as can be seen in the helper class of that module

/**
     * Get Captcha
     *
     * @param string $formId
     * @return Mage_Captcha_Model_Interface
     */
    public function getCaptcha($formId)
    {
        if (!array_key_exists($formId, $this->_captcha)) {
            $type = $this->getConfigNode('type');
            $this->_captcha[$formId] = Mage::getModel('captcha/' . $type, array('formId' => $formId));
        }
        return $this->_captcha[$formId];
    }

so Mage_Captcha_Model_Recaptcha does not actually exist, which means I cannot use this....BUT, if, I place a rewrite directive in my module for that class/file, to a model class in my module, I can intercept the model instantiation, and successfully instantiate my class.

<captcha>
   <rewrite>
      <recaptcha>MyNamespace_MyModule_Model_Recapthca</recaptcha>
   </rewrite>
</captcha>

Considering how rewrites work, I do think there is not any need for magento's rewrite system to check (or care) that a file exists to rewrite it.

Magento get the rewrite directive, and instantiates the new model class instead of the original (even if it does not exist)

So, is this a bug, or a feature? Should I not depend on this ability? It does, however, open up some possibilities on extending some poorly written core functionality (like this captcha system)

EDIT: I released a module that resulted in this question happening. The module is a nice drop-in replacement of core captcha with googles reCaptcha

http://www.proxiblue.com.au/blog/magento-recaptcha/

https://github.com/ProxiBlue/recaptcha

4

I'd say the "bug" here is a poorly implemented configurable class feature in the Mage_Captcha module -- although it could be argued the developer did this specifically to restrict capcha class to the capcha model group, and therefore also restrict it to the Mage_Capcha module. If that's the case, this developer didn't comprehend the power of a fully operational Magento rewrite system.

Magento's rewrite feature is designed to allow a rewrite of any class irrespective of code pool, so I'd say that's a feature, and you should be able to rely on it. A few caveats follow.

The one thing you left out of your post is how you plan on changing

<type>zend</type> 

to

<type>recapcha</type> 

If you're going to change this directly in Mage_Capcha, or you're going to use the core_config_data table and/or system configuration fields, you'll run into a problem if this configuration exists, but your module with the rewrite is disabled/removed. Your module is removed, Magento tried to instantiate a capcha/recapcha model, can't find it, dies.

So make sure you replace this value either by creating the same node structure in your module such that your value is merged over the above value, or by (at runtime) dynamically replacing the value in the configuration with with Mage::getConfig()->setNode().

Finally, if it was me, since you need a rewrite to do this anyway, I'd just rewrite the getCaptcha function in the capcha/data helper class to instantiate the model you want.

  • I actually have that as a selectable option via system.xml in my module. Thus in magento admin you can select reCaptcha or Zend. – ProxiBlue Jul 29 '14 at 23:45
  • @ProxiBlue If that's the case, consider the use case where someone sets reCaptcha, but then uninstalls your module without setting the configuration back to Zend. Magento can't find the capcha class and then explodes. – Alan Storm Jul 29 '14 at 23:58
  • 1
    @AlanStorm Perfect argument for Magento needing an uninstaller for modules! – Joseph Leedy Jul 30 '14 at 0:39
  • @AlanStorm In regards to just extending the helper class. I did consider that. One of my #1 goals when making modules is not to use rewrites (if can be helped) - I always try and use events - results in more code, but better compatibility. In this case the rewrite of the non existing recaptcha class would prevent a potential conflict with another module rewriting the existing core class. Most likely not going to happen, but is possible. My question is more in general about the ability to have extended a class via rewrite that does not actually exist. - Feature, or Bug ;) – ProxiBlue Jul 30 '14 at 1:25
  • @AlanStorm Very good point in regards to the fact about my module being removed. I will thus reconsider how I set the type variable based upon your excellent suggestions. – ProxiBlue Jul 30 '14 at 1:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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