Do something like “svn export” with git

Zend framework recently moved to git and I'm starting to integrate it into our release scripts.
The previous command used svn export and the tag for the release I wanted.
It took a little while to figure out how to do this with git:

git clone --depth 1 --branch release-1.12.3 https://github.com/zendframework/zf1.git /where/do/you/want/it/zf1/1.12.3/
rm -f -r /var/www/vhosts/ZendFramework/1.12.3/.git

A few differences from svn:

  • git has the complete revision history in every checkout. By adding the –depth 1, we're only getting the history relevant to our selected 'branch' and greatly speeding up the checkout of this giant project.
  • git doesn't do tags like svn/cvs. A tag isn't a branch, its a human friendly name for a revision hash. The command is –branch but it doesn't have to be a branch. It can also be a tag or commit hash. You'll get a warning about head being disconnected, its not relevant in my case because I'm not making change to or managing this folder with .git after I get it checked out.
  • git doesn't have an 'export' method because it doesn't need it. All the git revisions are in the .git folder in the root of the project instead of spread all over kingdom come like cvs and svn. Just delete the .git folder and now the project is no longer under git revision control. ( Modern versions of svn have a single folder, just like git. Thanks Alan. )

This helped a lot and has other possible solutions.
http://stackoverflow.com/questions/160608/how-to-do-a-git-export-like-svn-export

Use PHP-CLI to publish server stats via json

If you need great server monitoring, use copper egg. It inexpensive, easy to install and very very good.

If you happen to use PHP with Linux, a lot of usesful information can be extracted from the /proc filesystem. Enough to provide basic monitoring. The attached script dumps and processes the output from proc every minute as json.

Make sure to protect the directory you're outputing this into to.

Download livestats.php code

Is this a private IP address?

I need to show different content to folks who are outside our network.
This snippet will detect a private ip address using php's built in filter class.

function is_private_ip($ip) {
return !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
}

FILTER_FLAG_NO_PRIV_RANGE gets you:

"Fails validation for the following private IPv4 ranges:10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.

Fails validation for the IPv6 addresses starting with FDor FC."

and FILTER_FLAG_NO_RES_RANGE gets you:

"Fails validation for the following reserved IPv4 ranges:0.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24 and224.0.0.0/4. This flag does not apply to IPv6 addresses."

Source: PHP Docs

Creating a Magento Payment Module – Part 3 – Model, Controllers and Events

There are many tutorials out there which show parts of implementing a payment module. None completely build the module. They all stop short of showing how they implemented their nameless payment method.

This is part 3 of the tutorial. Here's part 1 and part 2 in case you missed them.

This post will walk through the model, action controllers and how they interact with the mockpay api.

My/Mockpay/Model/Standard.php

This model extends Mage_Payment_Model_Method_Abstract and if you look at the code of the base model, you'll see it has a lot of protected boolean attributes. These attributes are probed by the various consumers of these payment methods to figure out which features of the payment API our module supports.

Most of the modules I looked at for examples do this by overriding the properties instead of just setting them in the constructor. Our model defines four properties:

  • $_canUseForMultiShipping which enables/disables this method to be used for orders split up and shipped to many addresses,
  • $_canUseInternal which enables/disables using this method from the admin order screen,
  • $_code which is the unique payment method code for this module. It should match the code defined in the config.xml file. Its just text.
  • $_isInitializeNeeded, which enables a call to the initialize method when payment is captured.

The model::initialize() method is called when the order is placed. (Last step of the checkout process when the "place order" button is clicked.)
Looking at other modules is a great way to figure out how this code should work and if you look at the paypal or authorize.net modules you'll find a bunch more options are configured. These modules do the full authorize/capture process. Authorize occurs when the payment method is selected and the capture method is called when you click the "place order" button is clicked.

My module is very simple, needed only one method to be called at the very end of the payment process.
I opted to use initialize() instead of capture/authorizenbsp;because it always occurs at the same point in the process and I observed that initialize is only called in one place. I didn't find that to be true of the other methods.

In my initialize method, I'm setting the order state to "pending payment". This provides a clue to the folks working with the order in the backend that no payment has been collected for this order yet. I'm also connecting to the mockpay api and sending the order details. Mockpay will respond by providing a session token which will be unique to this order. The token is used to associate the customer on our site to the order details on the mockpay site with the order info and amount we're requesting. This is also where we'll inform mockpay about the cancel, error and success urls for this order.

Once payment is completed or canceled. The customer will be redirected back to our site. At that point we have a little more work to do with the order to either make an invoice and change the order state if successful or cancel it if the order fails or is canceled.

We'll use action controllers to handle these requests.

These are in the controllers/StandardController.php file. This is also extending an existing magento resource called "Mage_Core_Controller_Front_Action".

The successAction() will handle the success condition of the api where payment was completed successfully.
We'll get a token back from the mockpay api and we'll be able to use the token to query the api to get more details about the payment.

If everything checks out, we can change the state of the order from STATE_PENDING_PAYMENT to STATE_NEW, so its ready for someone on the store to ship and complete. This is also where we'll convert the quote into an invoice and mark it as paid. I skipped this step in the first version and it means someone on the backend has to do the extra step of creating an invoice and marking it as paid in magento.

Once all these steps are completed, I can then redirect the customer to the order complete page.

The other possible conditions are cancel, the person doesn't want to pay or failure where payment can't be completed because of lack of funds. I have these two conditions routed to the same action, the cancelAction().

Cancel will make the quote inactive and call the order objects cancel method.

With these actions in place, we have a functional payment module integrated with the mock pay api.

I've tried to comment as much as possible in the code so hopefully it will be instructive as you attempt to create your own payment method.

The full code for this payment module can be found on github.

Creating a Magento Payment Module – Part 2 – Module structure

There are many tutorials out there which show parts of implementing a payment module. None completely build the module. They all stop short of showing how they implemented their nameless payment method. These holes made something which should have taken a day or so to work out take two weeks to complete. Most of that time was spent figuring out the "Magento way" to do things. Once that was established, the module itself is very small. 6 files and 300 lines of code.

The previous post created a fake payment gateway. Part 2 will cover the structure of your magento module and part 3 will discribe how magento and the api interact.

The completed module can be downloaded from github.

Magento module file structure

Magento's file structure is based on the PEAR/Zend Framework autoloader where class xx_yyy_zz relates directly to a physical file of ./xx/yyy/zz.php.
Our module will use the namespace/folder structure of My_Mockpay_*

Example folder structure:

[My]
     [Mockpay]
          [controllers]
          [etc]
          [Model]
          [Helper]
          [Block]

Controllers are related to Zend_Action_Controllers.
In this example, we'll have one controller action for each possible response of the api: Success, Cancel and Failure.

Model is for your model code and business logic.
We'll extend Mage_Payment_Model_Method_Abstract, create a custom observer to hook into events which are fired during checkout, and create a custom class which will talk to our mockpay soap API.

Helper is for custom Mage_Payment_Helper_* classes. Only one helper is required and it need not be customized.
We'll extend Mage_Payment_Helper_Data.

Block is for custom code which alters the display of our payment method.
In this example, we're going to use the default block so this folder will be empty.

Etc contains the config files which glue the module together.

System.xml is for configuring the back-end of your module.
The args defined here will have a UI for editing them in the System->config->Payment Methods screen automatically.

Config.xml lets Magento know what the module is supposed to do and which files to load.

Lets take a look at Config.xml

the root element is

<config>
    
    <modules?
        <My_Mockpay>
            <version>0.1.0</version>
        </My_Mockpay>
    </modules>

You set the module version here. It's important later when the next version of your module is released.
(Which is outside the scope of this tutorial. We don't need a custom database table so upgrading is irrelevant.)

Then start the

<global>

section.

        <models>
            <mockpay>
                <class>My_Mockpay_Model</class>
            </mockpay>
        </models>

This registers a route to your model files in Magento.

        <helpers>
            <mockpay>
                <class>My_Mockpay_Helper</class>
            </mockpay>
        </helpers>

Ditto for the helpers.

        <payment>
            <groups>
                <mockpay>Mockpay</mockpay>
            </groups>
        </payment>

This lets mageto know this is a payment module.

        <events>
            <checkout_type_onepage_save_order_after>
                <observers>
                    <my_mockpay_observer>
                        <class>My_Mockpay_Model_Observer</class>
                        <method>saveOrderQuoteToSession</method>
                    </my_mockpay_observer>
                </observers>
            </checkout_type_onepage_save_order_after>
        </events>

Events are triggered at specific points in the code and allow you to attach custom code to an event without overriding it. In the example, the "checkout_type_onepage_save_order_after" event is a part of one-page checkout and is fired right after the order is created, but before the redirect to the payment form.
That's the end of the global section of the config.xml

The default section establishes the default values for the fields defined in system.xml file.

    <default>
        <payment>
            <mockpay>
                <model>mockpay/standard</model>
                <group>mockpay</group>
                <active>1</active>
                <title>Credit Card (MockPay - Fake Payment Gateway) </title>
                <payment_action>sale</payment_action>
                <allowspecific>0</allowspecific>
            </mockpay>
        </payment>
        <mockpay>
            <settings>
                <activationstatus>0</activationstatus>
            </settings>
        </mockpay>
    </default>

The last section of my file is the front-end

    <frontend>
        <secure_url>
            <mockpay_processing>/mockpay/standard</mockpay_processing>
        </secure_url>
        <routers>
            <mockpay>
                <use>standard</use>
                <args>
                    <module>My_Mockpay</module>
                    <frontName>mockpay</frontName>
                </args>
            </mockpay>
        </routers>
    </frontend>

Here we're registering a route to the controller for magento to use.
When the module is installed its actions will be accessible from:

http://domain.tld/magento/index.php/mockpay/standard/action/param/value/param2/value2 ...

This defines where the files will go an what we need to do.
Lets take a look at the system.xml

Each child node of

<fields>

is a field of data which will be save into the "core_config" table in the magento database.
The configuration option for your module should go here. You'll be able to edit these values from the magento configuration panel in thte back-end
and retrieve these values in your module. The sample file includes the options you'd see most often when configuring a new module.

Take note of the "merchantkey" element:

                        <merchantkey translate="label">
                            <label>Merchant Key</label>
                            <comment><![CDATA[Data entered into this field is stored encrypted in the db.]]></comment>
                            <frontend_type>text</frontend_type>
                            <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
                            <sort_order>51</sort_order>
                            <show_in_default>1</show_in_default>
                            <show_in_website>1</show_in_website>
                            <show_in_store>0</show_in_store>
                        </merchantkey>

The name of the element is arbitrary. You get to pick.
Each field has a label, optional comment, type, model, order and visibility options.
This data is stored in the core_config table in the database.

If your saving passwords or sensitive information here, use the "system_config_backend_encrypted" back-end. (aka Mage_Adminhtml_Model_System_Config_Backend_Encrypted)
This stores your data in the core_config table encrypted and prevents prying eyes from discovering sensitive information like api username or keys.

You can see the other back-ends by browsing the "/Mage/Adminhtml/Model/System/Config/Backend" folder.

The final config file is the module config file, called "My_Mockpay.xml". This file is normally stored in the "magento/app/ete/module" folder and enables the module withinMmagento. If you need to remove the module, delete this file and clear the Magento cache.

We'll dive into the controller and event modules in part 3.