使用者情境:批量使用 CSV 匯入 ubercart 訂單
Feeds 模組已經有一個 CSV 格式讀取 parser,又有批量 batch 支持,能處理大檔案 CSV ,Feeds 的代碼也有很多使用的經驗,而且最重要的是,模組自己已經有四種內容可以匯入:(nodes, users, terms, feednode?),有更高的機會支持其他內容 (ubercart orders)
先從 “The developer's guide to Feeds” 開始研究:(https://www.drupal.org/node/622700)
有三種 plugin: fetcher,parser 和 processor
- Fetcher 是「獲得匯入源的方法」feeds module 已經有一個檔案上載的 fetcher
- Parser 是「如何分析,讀取匯入源」feeds module 已經有一個 CSV parser
- Processer 的工作是將處理過的資料儲存成為 Drupal 的內容
建立一個新模組 ubercart_order_feeds.module:
<?php
/**
* Implementation of hook_feeds_plugins().
* http://drupalcontrib.org/api/drupal/contributions%21feeds%21feeds.api.php/function/hook_feeds_plugins/6
*/
function ubercart_order_feeds_feeds_plugins() {
$path = drupal_get_path('module', 'ubercart_order_feeds');
$info = array();
$info['FeedsOrderProcessor'] = array(
'name' => 'Order processor',
'description' => 'Create orders.',
'help' => 'Create orders from parsed content.',
'handler' => array(
'parent' => 'FeedsProcessor',
'class' => 'FeedsOrderProcessor',
'file' => 'FeedsOrderProcessor.inc',
'path' => $path,
),
);
return $info;
}
?>
建立一個新檔案 FeedsOrderProcessor.inc:
<?php
class FeedsOrderProcessor extends FeedsProcessor {
}
?>
首先在 getMappingTargets()
定義 CSV 中會用到的欄位:
<?php
/**
* Return available mapping targets.
*/
public function getMappingTargets() {
$targets = array(
'sku' => array(
'name' => t('Product SKU'),
'description' => t('SKU of the product.'),
),
'quantity' => array(
'name' => t('Quantity'),
'description' => t(''),
),
'cost' => array(
'name' => t('Cost'),
'description' => t(''),
),
'delivery_first_name' => array(
'name' => t('Delivery: First name'),
'description' => t(''),
),
'delivery_last_name' => array(
'name' => t('Delivery: Last name'),
'description' => t(''),
),
//....
?>
在 CSV 內的資料處理過之後,資料的值會根據 Array 的 key 放到 object 之內.
我輸出了一個原生的 order object,找出原本就有的預設欄名,定義 mappings 的時候重用它們,以省卻一點點麻煩 (i.e. delivery_first_name, delivery_last_name above and more)
process()
是主要的程式進入點,複製一點 NodeProcessor 的代碼:
<?php
public function process(FeedsImportBatch $batch, FeedsSource $source) {
// Count number of created and updated nodes.
$created = $updated = $failed = 0;
while ($item = $batch->shiftItem()) {
// Map item to a term.
$order = $this->map($batch);
//.......
?>
來到這一點出現一個新的函數 map()
來返回一個全新的 ubercart order object:
<?php
/**
* Execute mapping on an item.
*/
protected function map(FeedsImportBatch $batch, $target_order = NULL) {
// Prepare user account object.
if (empty($target_order)) {
$order = uc_order_new($user->uid, 'completed');
}
// Have parent class do the iterating.
return parent::map($batch, $order);
}
?>
parent::map()
函數會將 CSV 內的資料處理過之後,根據 mapping array 的 key 放到 object
程式化的建立 order
process()
的下一步是將 product 加到 order,並儲存之
使用 vid 載入一個 product: <?php uc_product_load() ?>
http://drupalcontrib.org/api/drupal/contributions!ubercart!uc_product!uc...
加 product 到 order:<?php $order->products[] = $product; ?>
再填入一些 order 的基本 mail 和 payment method 之後,儲存,完成 sale:
<?php
uc_order_save($order);
uc_cart_complete_sale($order, TRUE);
?>
你亦可以加入 payment method<?php uc_payment_enter($order->order_id, 'bank_transfer', 0, 0, NULL, t('Checkout completed for a free order.')); ?>
Github 源碼 repo: https://github.com/joetsuihk/ubercart_order_feeds
One more thing
Processor 可以有自己的設定頁面
在我的情境,因為客戶會將同一個模組放到不同的網站,而他們有不同的 webform node ID
所以我便將 ID 放到設定頁面令客戶可以更方便的修改設定了
<?php
/**
* Override parent::configDefaults().
*/
public function configDefaults() {
return array(
'card_form_id' => '',
'mappings' => array(),
);
}
public function configForm(&$form_state) {
$form = array();
$form['card_form_id'] = array(
'#type' => 'textfield',
'#title' => t('Card webform node ID'),
'#default_value' => $this->config['card_form_id'],
);
return $form;
}
?>
Attachment | Size |
---|---|
Screen Shot 2014-08-04 at 12.34.33 pm.png | 56.24 KB |