Extending the Magento OnePage checkout class
I am adding an additional checkbox field to the Magento checkout for newsletter subscriptions via a new module.
So far I have added the code to my layout file (billing.phtml):
<p>Please untick this box if you do not wish to receive infrequent email updates and newsletters from us. <input type="checkbox" name="billing[is_subscribed]" title="" value="1" id="billing:is_subscribed" class="checkbox" checked="checked" /></p>
I have extended the class (app/code/local/Clientname/Checkout/Model/Type/Onepage.php
) - I have extended only the savebilling method:
<?php
/**
* Magento
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@magentocommerce.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade Magento to newer
* versions in the future. If you wish to customize Magento for your
* needs please refer to http://www.magentocommerce.com for more information.
*
* @category Mage
* @package Mage_Checkout
* @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
*/
/**
* One page checkout processing model
*/
class Eatyourwords_Checkout_Model_Type_Onepage extends Mage_Checkout_Model_Type_Onepage
{
public function saveBilling($data, $customerAddressId)
{
if (empty($data)) {
return array('error' => -1, 'message' => $this->_helper->__('Invalid data.'));
}
$address = $this->getQuote()->getBillingAddress();
if (!empty($customerAddressId)) {
$customerAddress = Mage::getModel('customer/address')->load($customerAddressId);
if ($customerAddress->getId()) {
if ($customerAddress->getCustomerId() != $this->getQuote()->getCustomerId()) {
return array('error' => 1,
'message' => $this->_helper->__('Customer Address is not valid.')
);
}
$address->importCustomerAddress($customerAddress);
}
} else {
// process billing address and validate form
/* @var $addressForm Mage_Customer_Model_Form */
$addressForm = Mage::getModel('customer/form');
$addressForm->setFormCode('customer_address_edit')
->setEntity($address)
->setEntityType('customer_address')
->setIsAjaxRequest(Mage::app()->getRequest()->isAjax());
// emulate request object
$addressData = $addressForm->extractData($addressForm->prepareRequest($data));
$addressErrors = $addressForm->validateData($addressData);
if ($addressErrors !== true) {
return array('error' => 1, 'message' => $addressErrors);
}
$addressForm->compactData($addressData);
if (!empty($data['save_in_address_book'])) {
$address->setSaveInAddressBook(1);
}
}
// validate billing address
if (($validateRes = $address->validate()) !== true) {
return array('error' => 1, 'message' => $validateRes);
}
$address->implodeStreetAddress();
if (true !== ($result = $this->_validateCustomerData($data))) {
return $result;
}
if (!$this->getQuote()->getCustomerId() && self::METHOD_REGISTER == $this->getQuote()->getCheckoutMethod()) {
if ($this->_customerEmailExists($address->getEmail(), Mage::app()->getWebsite()->getId())) {
return array('error' => 1, 'message' => $this->_customerEmailExistsMessage);
}
}
if (!$this->getQuote()->isVirtual()) {
/**
* Billing address using otions
*/
$usingCase = isset($data['use_for_shipping']) ? (int)$data['use_for_shipping'] : 0;
switch($usingCase) {
case 0:
$shipping = $this->getQuote()->getShippingAddress();
$shipping->setSameAsBilling(0);
break;
case 1:
$billing = clone $address;
$billing->unsAddressId()->unsAddressType();
$shipping = $this->getQuote()->getShippingAddress();
$shippingMethod = $shipping->getShippingMethod();
$shipping->addData($billing->getData())
->setSameAsBilling(1)
->setShippingMethod($shippingMethod)
->setCollectShippingRates(true);
$this->getCheckout()->setStepData('shipping', 'complete', true);
break;
}
}
$this->getQuote()->collectTotals();
if (isset($data['is_subscribed'])) {
$status = Mage::getModel(‘newsletter/subscriber’)->subscribe($data['email']);
}
$this->getQuote()->save();
$this->getCheckout()
->setStepData('billing', 'allow', true)
->setStepData('billing', 'complete', true)
->setStepData('shipping', 'allow', true);
return array();
}
}
Specifically towards the bottom of the class I have inserted:
if (isset($data['is_subscribed'])) {
$status = Mage::getModel(‘newsletter/subscriber’)->subscribe($data['email']);
}
I have added a file to let Magento know about the module (app/etc/modules/Clientname_Checkout.xml
):
<?xml version="1.0"?>
<config>
<modules>
<Clientname_Checkout>
<active>true</active>
<codePool>lo开发者_C百科cal</codePool>
</Clientname_Checkout>
</modules>
</config>
However I am now stuck on the final step of how I get Magento to recognise and use the alernative save_billing method I have extended. I think I need to add a file /app/code/local/Clientname/config.xml
.
But I don't understand how I set this up so that the new savebilling class is used instead of the original.
Please can somebody help with this final step?
Thanks
Simon
This is a textbook example of class overrides in Magento. As you probably know, Magento uses a form of abstraction to load classes based on the contents of the XML configuration files dotted around the codebase. This means we can load the model Mage_Checkout_Model_Type_Onepage
by calling Mage::getModel('checkout/type_onepage')
, with the default configuration. A pretty cool feature is the ability to modify the mapping of the model reference, checkout/type_onepage
to the actual class name.
Directory Structure
So you've done the hard work: editing the template and changing the model method. Next you need to build a small module to perform the class rewriting. Based on the name of your class, you're going to need a directory structure of the form:
/app
/etc
/modules
/Eatyourwords_Checkout.xml
/code
/local
/Eatyourwords
/Checkout
/etc
/config.xml
/Model
/Type
/Onepage.php
Performing the rewrite
The rewrite is handled in your module configuration file, config.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<eyw_c>
<version>1.0</version>
</eyw_c>
</modules>
<global>
<models>
<eyw_c>Eatyourwords_Checkout_Model</eyw_c>
<checkout>
<rewrite>
<type_onepage>Eatyourwords_Checkout_Model_Type_Onepage</type_onepage>
</rewrite>
</checkout>
</models>
</global>
</config>
The stuff in the <modules />
tag group is just some standard bootstrapping for the module.
In the <models />
section we are defining namespace to be used when loading any of our Model classes. Much like the checkout/type_onepage
, we can access any models we have in our /Model
directory by appending eyw_c/*
.
We then open up the Mage_Checkout
model namespace, <checkout />
, and perform a rewrite of the checkout/type_onepage
class. Now when Magento attempts to load checkout/type_onepage
it will look for our class. All other checkout/*
classes will be unaffected. The class name for them will be constructed in the normal manner.
Enable the module
Next we need to point Magento to the new module that we've created. Your attempt was almost correct. You should call it Eatyourwords_Checkout.xml
and place it in /app/etc/modules
:
<?xml version="1.0"?>
<config>
<modules>
<Eatyourwords_Checkout>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Checkout />
</depends>
</Eatyourwords_Checkout>
</modules>
</config>
..and that's it done. Class overridden.
精彩评论