Drupal Enhancements – Sell Content

Many of you out there probably tried to create custom actions for your Drupal site.
The reason behind that, was probably because you want to enhance your Drupal functionality so it will fit your new module requirements.

Within this blog post I’ll show a quick and easy way for adding new “api action” for your module to sale content.
This tutorial applicable for any “API” you want to create between your site and the world outside.

This tutorial includes:
1. Handling files on remote ftp.
2. Processing the content.
3. Sending approval email.

Imagine that you have several virtual shops. One in Amazon, and one in eBay.
Now you have develop new virtual shops for your products and you want to import your products in an automated way. All you need is to create a gate between your site and every other shop that you manage, to share content and any other useful data.
The easy and fast solution is to create an “API” to your Drupal site with secret code that will automate this process.
Below you can see a scheme of the process
Virtual Shop blog - New Page

So lets get to work…

1. Create new content type for the virtual shops.

There are 6 required fields: Shop name, email, Ftp url, Ftp password, Ftp username, and Secret Key.
* You can add any metadata you want to this content type.

2. Design the structure for the XML.

Lets assume we are selling videos so our xml will probably have the following tags:
Video name, Price, Description, Tags, Author, Film maker and many more metadata.

3. Create new menu link which will serve us as the Endpoint api.

This is the new “action” we’re adding for our Drupal.
We’ll use hook_menu for this process.

function mymodule_menu() 
{
$items['process_shop_order'] = array(
            Strings::PAGE_TITLE => 'Process Shop Order',
            Strings::PAGE_CALLBACK => 'processVirtualShopOrder',
            Strings::ACCESS_CALLBACK => 'hasShopRole',
            Strings::IS_EXPANDED => true,
            Strings::MENU_FILE => 'actions' . DIRECTORY_SEPARATOR . 'ShopActions.php',
            Strings::MENU_TYPE => MENU_CALLBACK
        );
	return $items;
}

The “process_shop_order” will serve as the endpoint which will later be used by the cron job.

4. Process Order.

This step is divided for 5 smaller steps: Check key, FTP connect, Parse XML, Process Order, Send EMail.
All these steps will take place in the callback function as defined in hook_menu, in our example “’processVirtualShopOrder’”.

I will go over the steps quickly without code examples.
If you have any doubts in every steps and you still need code examples just comment below with where you’re stuck and what you’re trying to achieve and I’ll send back the code sample for your issue.

I. Check Key.

Every Time we create a new virtual shop it should have an api key (can be automatic generated or manually entered by the user). this key must be unique.
In our ftp we’ll add another cron job which will run every 2 minutes and we’ll call the “action” that we’ve created above with the api key. Example:
*/2 * * * * root wget -O –q -t 1 /process_orders?cron_key=3LwBmE_y2f02Pf27bHT5XqSd5OESakB158MbN9btUs0?apiKey=
This cron example will call the service every 2 minutes with the cron key and api key.
In our callback function “processVirtualShopOrder” as defined in hook_menu, we will be waiting for every call and we’ll check the api key against the api key in our database.
If they are match we will proceed for the next step.

II. FTP connect

Now we will connect to the remote ftp with the defined parameters of that virtual shop.
We can determine which virtual shop made the call via the api key and then we can retrieve all the necessary information such as ftp url, username, and password.
We’ll fetch the new xml file that is waiting to be processed and after successful iteration we will move him to processed directory.

III. Parse XML

We’ll create a function which will parse the xml in the structure that we decided.
XML Example:

<ROOT>
	<VIDEOS>
		<VIDEO>
			<NAME>No more manual changes</NAME>
			<DESCRIPTION>Automatic integration</DESCRIPTION>
			<AUTHOR>Roy Cohen</AUTHOR>
			<STARRING>Roy Cohen</STARRING>
			…. The entire metadata you want to include
		</VIDEO>
		<VIDEO>
			<NAME>Daredevil</NAME>
			<DESCRIPTION>American superhero who saves the world</DESCRIPTION>
			<AUTHOR>Mark Steven Jhonson</AUTHOR>
			<STARRING>Ben Affleck and Jennifer Garner</STARRING>
			…. The entire metadata you want to include
		</VIDEO>
	</VIDEOS>
<ROOT>

IV. Process Order

Every VIDEO item in the xml will serve as 1 node entity so after parsing the xml we’ll create 1 node for every video.

V. Send EMail.

On successful creation of the xml content we’ll send email to the shop owner email (we can retrieve this information from the virtual shop node) with the new nodes that has been created.

Below you can see a demo code for “processVirtualShopOrder” without the sub-functions.

public function getOrdersFromFtp()
    {
        $xmlParser = new OrderXMLParser();
        $ftpClient = new FTPClient();

        // Connect to ftp.
        $ftpClient->connect(Conf::get('ftp.server'), Conf::get('ftp.user'), Conf::get('ftp.password'));

        // Create processed orders directory.
        $ftpClient->createDir(self::PROCESSED_ORDERS_PATH);

        // List orders.
        $orders = $ftpClient->listDir(self::ORDERS_PATH);

        foreach ($orders as $orderFile)
        {
            $orderPath = self::ORDERS_PATH . '/' . $orderFile;

            try
            {
                // Get file content as string.
                $orderString = $ftpClient->getFileContents($orderPath);

                // Parse order.
                $order = $xmlParser->parse($orderString);

                // Process order.
                $this->processOrder($order);

                // Move file to processed dir.
                $dest = self::PROCESSED_ORDERS_PATH . '/' . $orderFile;
                $ftpClient->moveFile($orderPath, $dest);

                $this->log->info(__METHOD__, 'Processed order: ' . $orderFile);
            }
            catch (Exception $e)
            {
                $this->log->error(__METHOD__, "Failed processing order $orderFile: " . $e->getMessage());
            }
        }
    }

One thought on “Drupal Enhancements – Sell Content

Leave a Reply

Your email address will not be published. Required fields are marked *