Rewrite in Custom Module to Non-Existing Core Class Model

overrides

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

Best Answer

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.