diff --git TODO.txt TODO.txt deleted file mode 100644 index d5cf75f..0000000 --- TODO.txt +++ /dev/null @@ -1,17 +0,0 @@ -$Id$ - -API -* Handle update/delete cases cleanly (currently inefficient) - -Search -* Paged searching -* Advanced search options -* Properly themed search results - -Theming -* Document variables - -Functionality -* Wish lists (separate module? -* Related Books block for nodes (separate module?) -* Reading List module (separate module?) diff --git aat_legacy/aat_legacy.d5-migrate.inc aat_legacy/aat_legacy.d5-migrate.inc deleted file mode 100644 index 2b11b52..0000000 --- aat_legacy/aat_legacy.d5-migrate.inc +++ /dev/null @@ -1,66 +0,0 @@ -nid] = $node->title; - - $context['sandbox']['progress']++; - $context['sandbox']['current_node'] = $node->nid; - $context['message'] = t('Processing nid %nid, %title', array('!url' => url("node/$node->nid"), '%nid' => $node->nid, '%title' => $node->title)); - } - } -} -/** - * Batch 'finished' callback - */ -function _aat_legacy_migrate_fields_finished($success, $results, $operations) { - if ($success) { - $message = t('%count legacy fields (amazonnodes and links) were imported.', array('%count' => count($results))); - $message .= theme('item_list', $results); - } - else { - // An error occurred. - // $operations contains the operations that remained unprocessed. - $error_operation = reset($operations); - $message = t('An error occurred while processing %op. with arguments = %args.', array('%op' => $error_operation[0], '%args' => print_r($error_operation[0], TRUE))); - } - drupal_set_message($message); -} - -/** - * Process one node. - * @param $nid - * The nid to which we are to add values. - * @param $type - * The ntype field from amazonnode table: the content type we're working with. - * @return - * the updated node. - */ -function _aat_legacy_migrate_from_d5($nid, $type) { - $results = db_query("SELECT asin, ntype FROM {amazonnode} an WHERE an.nid = %d and an.ntype = '%s'", $nid, $type); - $dirty = FALSE; - $node = node_load($nid); - - while ($asin = db_fetch_object($results)) { - // if (!in_array($asin->asin, array_keys(array_values($node->field_legacy_asin)))) { - $node->field_legacy_asin[]['asin'] = $asin->asin; - // } - } - node_save($node); - $sql = "DELETE FROM {amazonnode} WHERE nid = %d AND ntype = '%s'"; - db_query($sql, $nid, $type); - - return $node; -} \ No newline at end of file diff --git aat_legacy/aat_legacy.info aat_legacy/aat_legacy.info deleted file mode 100644 index ea7f0eb..0000000 --- aat_legacy/aat_legacy.info +++ /dev/null @@ -1,8 +0,0 @@ -; $Id$ -name = Amazon legacy importer -description = This module is used only to import legacy Drupal 5 Amazontools data. After upgrade it should be disabled. -package = Amazon -dependencies[] = amazon -dependencies[] = asin -core = 6.x -php = 5.2 diff --git aat_legacy/aat_legacy.install aat_legacy/aat_legacy.install deleted file mode 100644 index a76649e..0000000 --- aat_legacy/aat_legacy.install +++ /dev/null @@ -1,10 +0,0 @@ - "Amazontools Legacy Import", - 'page callback' => 'drupal_get_form', - 'access arguments' => array('administer site configuration'), - 'page arguments' => array('aat_legacy_import_form') - ); - return $items; -} - -/** - * Form to start the import process. - */ -function aat_legacy_import_form() { - $form = array(); - $form['explanation'] = array( - '#type' => 'markup', - '#prefix' => "
", - '#value' => t("Here you can import legacy Drupal 5 items from Amazon Tools. This may take a long time. It may be safely restarted."), - '#suffix' => "
", - ); - $form['submit'] = array( - '#type' => 'submit', - '#value' => t("Start import"), - ); - return $form; -} - -function aat_legacy_import_form_submit($form_state, &$form_value) { - aat_legacy_import_data(); -} - - -/** - * Create a CCK field for each node type that had Amazon link in D5. - * Then populate it. - */ -function aat_legacy_import_data() { - $ret = array(); - $result = db_query("SELECT DISTINCT type FROM node_type nt, amazonnode an where nt.type = an.ntype"); - // Build a list of fields that need data updating. - module_load_install('content'); - module_load_include('inc', 'content', 'includes/content.admin'); - module_load_include('inc', 'content', 'includes/content.crud'); - - $field = aat_legacy_legacy_field_description(); - - // First attach the new field to the content type. - $types = array(); - while ($type_ary = db_fetch_array($result)) { - $ntype = $type_ary['type']; - $types[] = $ntype; - $instance = content_field_instance_read(array('type_name' => $ntype, 'field_name' => 'field_legacy_asin')); - if (empty($instance)) { - drupal_set_message(t("Adding field_legacy_asin to node type %ntype", array('%ntype' => $ntype))); - $field['type_name'] = $ntype; - content_field_instance_create($field); - } - else { - drupal_set_message(t("field_legacy_asin already exists in node type %ntype; not creating it.", array('%ntype' => $ntype))); - } - } - - // Now batch-import the data from those items. - if (!empty($types)) { - $operations = array(); - $sql = "SELECT DISTINCT(nid) nid, ntype FROM {amazonnode} WHERE ntype IN (" . db_placeholders($types, 'varchar') . ") ORDER BY nid ASC"; - $result = db_query($sql, $types); - while ($item = db_fetch_object($result)) { - $operations[] = array('_aat_legacy_migrate_field_from_d5', array(array('nid' => $item->nid, 'ntype' => $item->ntype))); - } - $batch = array( - 'title' => t('Migrating amazonnode field values into field_legacy_asin CCK fields'), - 'operations' => $operations, - 'finished' => '_aat_legacy_migrate_fields_finished', - 'init_message' => t('Beginning migration of legacy_asin fields.'), - 'progress_message' => t('Processed @current out of @total.'), - 'error_message' => t('AAT Legacy field update encountered an error.'), - 'file' => drupal_get_path('module', 'aat_legacy') .'/aat_legacy.d5-migrate.inc', - ); - batch_set($batch); - } - if (empty($operations)) { - drupal_set_message(t("You have no items remaining to import. You may now disable the Amazon Legacy Importer module (aat_legacy).")); - } - -} - -/** - * Just returns field description for field_legacy_asin. - */ -function aat_legacy_legacy_field_description() { - return array ( - 'label' => 'Legacy ASIN', - 'field_name' => 'field_legacy_asin', - 'type' => 'asin', - 'widget_type' => 'asin_text', - 'change' => 'Change basic information', - 'weight' => '31', - 'description' => '', - 'default_value' => - array ( - 0 => - array ( - 'asin' => '', - ), - ), - 'default_value_php' => '', - 'default_value_widget' => NULL, - 'required' => 0, - 'multiple' => '1', - 'op' => 'Save field settings', - 'module' => 'asin', - 'widget_module' => 'asin', - 'columns' => - array ( - 'asin' => - array ( - 'type' => 'varchar', - 'length' => 32, - 'not null' => false, - ), - ), - 'display_settings' => - array ( - 'label' => - array ( - 'format' => 'above', - 'exclude' => 0, - ), - 5 => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - 'teaser' => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - 'full' => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - 4 => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - 2 => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - 3 => - array ( - 'format' => 'default', - 'exclude' => 0, - ), - ), - ); -} diff --git amazon-inline-item.tpl.php amazon-inline-item.tpl.php index e3fbb62..a6f9904 100644 --- amazon-inline-item.tpl.php +++ amazon-inline-item.tpl.php @@ -1,6 +1,6 @@ $item))) { print $output; } else { diff --git amazon.admin.inc amazon.admin.inc index ca1cb70..3445f8d 100644 --- amazon.admin.inc +++ amazon.admin.inc @@ -1,6 +1,6 @@ $data) { @@ -41,7 +41,7 @@ function amazon_settings_form($form_state) { $form['amazon_aws_access_key'] = array( '#type' => 'textfield', '#title' => t('Amazon AWS Access Key ID'), - '#description' => t('You must sign up for an Amazon AWS account to use the Product Advertising Service. See !more_info for information and a registration form.',array('!more_info'=>l(t('the AWS home page'),'https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key',array('html'=>TRUE)))), + '#description' => t('You must sign up for an Amazon AWS account to use the Product Advertising Service. See !more_info for information and a registration form.', array('!more_info' => l(t('the AWS home page'), 'https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key', array('html' => TRUE)))), '#default_value' => variable_get('amazon_aws_access_key', ''), '#required' => TRUE, ); @@ -49,18 +49,18 @@ function amazon_settings_form($form_state) { $form['amazon_aws_secret_access_key'] = array( '#type' => 'textfield', '#title' => t('Amazon AWS Secret Access Key'), - '#description' => t('You must sign up for an Amazon AWS account to use the Product Advertising Service. See !more_info for information and a registration form.',array('!more_info'=>l(t('the AWS home page'),'https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key',array('html'=>TRUE)))), - '#default_value' => variable_get('amazon_aws_secret_access_key',""), + '#description' => t('You must sign up for an Amazon AWS account to use the Product Advertising Service. See !more_info for information and a registration form.', array('!more_info' => l(t('the AWS home page'), 'https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key', array('html' => TRUE)))), + '#default_value' => variable_get('amazon_aws_secret_access_key', ""), '#required' => TRUE, ); // Now add the Javascript that does the fancy hide/show effects. - drupal_add_js(drupal_get_path('module', 'amazon') .'/amazon.admin.js'); + drupal_add_js(drupal_get_path('module', 'amazon') . '/amazon.admin.js'); return system_settings_form($form); } -function amazon_storage_settings_form() { +function amazon_storage_settings_form($form, &$form_state) { $period = drupal_map_assoc(array(3600, 7200, 14400, 21600, 43200, 86400), 'format_interval'); $form['details']['amazon_refresh_schedule'] = array( @@ -77,20 +77,23 @@ function amazon_storage_settings_form() { '#default_value' => variable_get('amazon_core_data', array('creators', 'images')), '#options' => array( 'creators' => t('Book authors, film actors, etc.'), - 'images' => t('Product images'), + 'images' => t('Product image links'), 'editorial_reviews' => t('Editorial reviews'), 'customer_reviews' => t('Customer reviews'), ), ); // Now add the Javascript that does the fancy hide/show effects. - drupal_add_js(drupal_get_path('module', 'amazon') .'/amazon.admin.js'); + drupal_add_js(drupal_get_path('module', 'amazon') . '/amazon.admin.js'); return system_settings_form($form); } - -function amazon_test_form($form_state) { +/** + * Form for testing a single ASIN. + * + */ +function amazon_test_form($form, &$form_state) { $form = array(); $form['asin'] = array( @@ -105,11 +108,11 @@ function amazon_test_form($form_state) { ); if (isset($form_state['amazon_item'])) { - $markup = theme('amazon_item', $form_state['amazon_item'], 'details'); - $markup .= '
'. print_r($form_state['amazon_item'], TRUE) .'
'; + $markup = theme('amazon_item', array('item' => $form_state['amazon_item'], 'style' => 'default')); + $markup .= '
' . print_r($form_state['amazon_item'], TRUE) . '
'; $form['item_data'] = array( '#type' => 'markup', - '#value' => $markup, + '#markup' => $markup, '#weight' => 10, ); } @@ -131,7 +134,8 @@ function amazon_test_form_submit($form, &$form_state) { // causes a serialization operation. Whoops. $form_state['amazon_item'] = $item; $form_state['rebuild'] = TRUE; - } else { + } + else { drupal_set_message(t("Test failed for this ASIN. Please check the !link for messages.", array('!link' => l(t("error log"), 'admin/reports/dblog')))); } } diff --git amazon.admin.js amazon.admin.js index 1dfc277..5f9579a 100644 --- amazon.admin.js +++ amazon.admin.js @@ -1,24 +1,28 @@ -// $Id$ +//$Id$ +Drupal.behaviors.amazon = { + attach: { -jQuery(document).ready(function(){ jQuery("#edit-amazon-associate-setting").bind("change", function() { - if (this.value == 'custom') { - $("#amazon-associate-id-wrapper").show('fast'); - } - else { - $("#amazon-associate-id-wrapper").hide('fast'); - } - return false; -}) -}); - -jQuery(document).ready( - function(){ jQuery("#edit-amazon-cache").bind("change", function() { - if (this.checked == true) { - $("#amazon-storage-details").show('fast'); - } - else { - $("#amazon-storage-details").hide('fast'); - } - return false; + jQuery(document).ready(function(){ jQuery("#edit-amazon-associate-setting").bind("change", function() { + if (this.value == 'custom') { + $("#amazon-associate-id-wrapper").show('fast'); + } + else { + $("#amazon-associate-id-wrapper").hide('fast'); + } + return false; }) -}); + }); + + jQuery(document).ready( + function(){ jQuery("#edit-amazon-cache").bind("change", function() { + if (this.checked == true) { + $("#amazon-storage-details").show('fast'); + } + else { + $("#amazon-storage-details").hide('fast'); + } + return false; + }) + }); +} +}; \ No newline at end of file diff --git amazon.info amazon.info index 959fe18..6e73357 100644 --- amazon.info +++ amazon.info @@ -1,5 +1,24 @@ name = Amazon API -description = Provides integration with the Amazon Ecommerce APIs. +description = Provides integration with the Amazon Product Advertising API. package = Amazon -core = 6.x +core = 7.x php = 5.2 + +files[] = amazon-inline-item.tpl.php +files[] = amazon-item-detail.tpl.php +files[] = amazon-item-details.tpl.php +files[] = amazon-item-thumbnail.tpl.php +files[] = amazon-item.tpl.php +files[] = amazon-views-view-row-item.tpl.php +files[] = amazon.admin.inc +files[] = amazon.install +files[] = amazon.module +files[] = amazon.theme.inc +files[] = includes/amazon.views.inc +files[] = includes/amazon_views_plugin_row_amazon_view.inc +files[] = includes/views_handler_field_amazon_date.inc +files[] = includes/views_handler_field_amazon_image.inc +files[] = includes/views_handler_field_amazon_participant.inc +files[] = includes/views_handler_field_amazon_title.inc +files[] = includes/views_handler_filter_amazon_node_module.inc +files[] = includes/views_handler_filter_string_compare.inc diff --git amazon.install amazon.install index 0518d15..dd54281 100644 --- amazon.install +++ amazon.install @@ -1,4 +1,10 @@ l(t("Amazon API Setttings"),'admin/settings/amazon')))); + drupal_set_message(t("The Amazon API must be configured with an Access Key ID and an Amazon AWS Secret Access Key to function. Go to !settings.", array("!settings" => l(t("Amazon API Setttings"), 'admin/settings/amazon')))); $requirement['title'] = t("Amazon AWS Secret Access Key"); $requirement['severity'] = REQUIREMENT_WARNING; $requirement['value'] = t("Not Set"); - $requirement['description'] = t("The Amazon API must be configured with an Access Key ID and an Amazon AWS Secret Access Key to function. Go to !settings.",array("!settings"=>l(t("Amazon API Setttings"),'admin/settings/amazon'))); - return array('amazon_aws_secret_access_key',$requirement); + $requirement['description'] = t("The Amazon API must be configured with an Access Key ID and an Amazon AWS Secret Access Key to function. Go to !settings.", array("!settings" => l(t("Amazon API Setttings"), 'admin/settings/amazon'))); + return array('amazon_aws_secret_access_key', $requirement); } return NULL; @@ -130,7 +137,7 @@ function amazon_schema() { 'nid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE), 'vid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE), 'asin' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE), - 'notes' => array('type' => 'text','not null' => FALSE), + 'notes' => array('type' => 'text', 'not null' => FALSE), 'module' => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => 'amazon'), 'delta' => array('type' => 'int', 'default' => 0), ), @@ -147,171 +154,12 @@ function amazon_schema() { } /** - * Update variables from legacy AAT module where possible. Add mpn field. - */ -function amazon_update_6001() { - $ret = array(); - db_add_column($ret, 'amazon_item', 'mpn', 'varchar(128)'); - - // If the access key is not set, and there is a D5 amazontools access key, use it. - $d6_aws_access_key = variable_get('amazon_aws_access_key', ""); - if (empty($d6_aws_access_key)) { - $old_access_key = variable_get('amazon_awsaccess_key', ""); - if (!empty($old_access_key)) { - variable_set('amazon_aws_access_key', $old_access_key); - variable_del('amazon_awsaccess_key'); - $ret[] = array('success' => TRUE, 'query' => 'Updated Amazon AWS Access Key from D5 AAT'); - } - } - // Bring over the d5 associate id if possible. - $d6_associate_id = variable_get("amazon_custom_associate_id", ""); - if (empty($d6_associate_id)) { - $associate_id = variable_get("amazon_associate_id", ""); - if (!empty($associate_id)) { - variable_set('amazon_custom_associate_id', $associate_id); - variable_set('amazon_associate_setting', 'custom'); - variable_del("amazon_associate_id"); - $ret[] = array('success' => TRUE, 'query' => 'Updated Amazon Associate ID from D5 AAT'); - } - } - if (is_numeric(variable_get('amazon_locale',"US"))) { - variable_del('amazon_locale'); - drupal_set_message(t("The Amazon locale setting was invalid. Please visit the Amazon settings page to correct it.", array('!url' => url('admin/settings/amazon')))); - } - - return $ret; -} - -function amazon_update_6002() { - $ret = array(); - // Make sure that primary keys are correct - db_drop_primary_key($ret, 'amazon_item_image'); - db_add_primary_key($ret, 'amazon_item_image', array('asin', 'size')); - return $ret; -} - -/** - * http://drupal.org/node/426786 - Allow longer image url fields. - */ -function amazon_update_6003() { - $ret = array(); - db_change_field($ret, 'amazon_item_image', 'url', 'url', - array('type' => 'varchar', 'length' => 128, 'not null' => TRUE)); - return $ret; -} - -/** - * Ugly hack for those updating from amazon module in D5. - */ -function amazon_update_6004() { - $ret = array(); - - if (!db_table_exists('amazon_item')) { - drupal_install_schema('amazon'); - $ret[] = array('success' => TRUE, 'query' => 'Force-installed Amazon module tables after botched D5 upgrade.'); - } - - return $ret; -} - -function amazon_update_6005() { - $ret = array(); - db_change_field($ret, 'amazon_item', 'detailpageurl', 'detailpageurl', - array('type' => 'text')); - db_change_field($ret, 'amazon_item', 'brand', 'brand', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'publisher', 'publisher', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'manufacturer', 'manufacturer', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'studio', 'studio', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'label', 'label', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'binding', 'binding', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'releasedate', 'releasedate', - array('type' => 'varchar', 'length' => 64)); - db_change_field($ret, 'amazon_item', 'productgroup', 'productgroup', - array('type' => 'varchar', 'length' => 255)); - db_change_field($ret, 'amazon_item', 'producttypename', 'producttypename', - array('type' => 'varchar', 'length' => 255)); - - return $ret; -} - -function amazon_update_6006() { - $ret = array(); - db_add_field($ret, 'amazon_item', 'invalid_asin', array('type' => 'int', 'default' => 0)); - return $ret; -} - -function amazon_update_6007() { - $ret = array(); - if (variable_get('amazon_associate_setting', 'associate') == 'author') { - variable_del('amazon_associate_setting'); // go with the default. - $ret[] = array('success' => TRUE, 'query' => t('Replaced "author" Amazon associate setting with the default.')); - } - return $ret; -} - -/** - * Change listpriceamount field to numeric. It's not floating anyway. - */ -function amazon_update_6008() { - $ret = array(); - db_change_field($ret, 'amazon_item', 'listpriceamount', 'listpriceamount', - array('type' => 'numeric')); - return $ret; -} - -/** - * Change key on amazon_item_node (again). - * - * It looks like nid should be the correct portion of the key, since there - * is no vid coming in. In fact... There should be no vid. - * - */ -function amazon_update_6009() { - $ret = array(); - db_drop_primary_key($ret, 'amazon_item_node'); - db_add_primary_key($ret, 'amazon_item_node', array('nid', 'asin', 'module')); - return $ret; -} - - -/** - * Change key on editorial reviews, since it shouldn't be primary. - */ -function amazon_update_6010() { - $ret = array(); - db_drop_primary_key($ret, 'amazon_item_editorial_review'); - db_add_index($ret, 'amazon_item_editorial_review', 'amazon_item_editorial_review', array('asin')); - return $ret; -} - -/** - * Add Customer Reviews table so we can handle that. - * @return unknown_type - */ -function amazon_update_6011() { - $schema = amazon_schema(); - if (!db_table_exists('amazon_item_customer_review')) { - db_create_table($ret, 'amazon_item_customer_review', $schema['amazon_item_customer_review']); - } - return $ret; -} - -/** - * Add new elements to the amazon_item table: Lowest price, etc. - * @return unknown_type + * Fix messed up type for currency code in update 6012. */ -function amazon_update_6012() { - db_add_field($ret, 'amazon_item', 'lowestpriceamount', array('type' => 'numeric')); - db_add_field($ret, 'amazon_item', 'lowestpricecurrencycode', array('type' => 'numeric')); - db_add_field($ret, 'amazon_item', 'lowestpriceformattedprice', array('type' => 'varchar', 'length' => 32)); - db_add_field($ret, 'amazon_item', 'amazonpriceamount', array('type' => 'numeric')); - db_add_field($ret, 'amazon_item', 'amazonpricecurrencycode', array('type' => 'numeric')); - db_add_field($ret, 'amazon_item', 'amazonpriceformattedprice', array('type' => 'varchar', 'length' => 32)); - return $ret; +function amazon_update_7100() { + db_change_field('amazon_item', 'lowestpricecurrencycode', 'lowestpricecurrencycode', + array('type' => 'varchar', 'length' => 32)); + db_change_field('amazon_item', 'amazonpricecurrencycode', 'amazonpricecurrencycode', + array('type' => 'varchar', 'length' => 32)); + return(t("Updated currency code column types")); } diff --git amazon.module amazon.module index a0a0db5..9a8c093 100644 --- amazon.module +++ amazon.module @@ -21,7 +21,7 @@ define('AMAZON_IMAGE_SIZES', 'SmallImage,MediumImage,LargeImage'); */ function amazon_menu() { $items = array(); - $items['admin/settings/amazon'] = array( + $items['admin/config/amazon'] = array( 'title' => 'Amazon API', 'description' => 'Global settings for the Amazon Ecommerce API.', 'page callback' => 'drupal_get_form', @@ -31,7 +31,7 @@ function amazon_menu() { 'access arguments' => array('administer amazon'), 'type' => MENU_NORMAL_ITEM ); - $items['admin/settings/amazon/storage'] = array( + $items['admin/config/amazon/storage'] = array( 'title' => 'Storage', 'description' => 'Local data storage settings for Amazon products.', 'page callback' => 'drupal_get_form', @@ -41,7 +41,7 @@ function amazon_menu() { 'access arguments' => array('administer amazon'), 'type' => MENU_LOCAL_TASK ); - $items['admin/settings/amazon/test'] = array( + $items['admin/config/amazon/test'] = array( 'title' => 'Test', 'page callback' => 'drupal_get_form', 'page arguments' => array('amazon_test_form'), @@ -50,14 +50,7 @@ function amazon_menu() { 'access arguments' => array('administer amazon'), 'type' => MENU_LOCAL_TASK ); - $items['admin/settings/amazon/upgrade'] = array( - 'page callback' => '_amazon_upgrade', - 'file' => 'amazon.admin.inc', - 'access callback' => 'user_access', - 'access arguments' => array('administer amazon'), - 'type' => MENU_CALLBACK - ); - $items['admin/settings/amazon/api'] = array( + $items['admin/config/amazon/api'] = array( 'title' => 'Settings', 'weight' => -10, 'type' => MENU_DEFAULT_LOCAL_TASK @@ -67,10 +60,15 @@ function amazon_menu() { } /** - * Implementation of hook_perm + * Implementation of hook_permission */ -function amazon_perm() { - return array('administer amazon'); +function amazon_permission() { + return array( + 'administer amazon' => array( + 'title' => t('Administer Amazon module'), + 'description' => t('Configure and test Amazon module.'), + ), + ); } /** @@ -79,19 +77,19 @@ function amazon_perm() { function amazon_theme() { $templates = array( 'amazon_item' => array( - 'arguments' => array('item' => array(), 'style' => 'default'), + 'variables' => array('item' => array(), 'style' => 'default'), 'pattern' => 'amazon_item__', 'template' => 'amazon-item', ), 'amazon_inline_item' => array( - 'arguments' => array('item' => array()), + 'variables' => array('item' => array()), 'template' => 'amazon-inline-item', // Re-use the existing infrastructure. 'preprocess functions' => 'amazon_preprocess_amazon_item', ), // Allows use of whatever is provided in preprocessed $variables. 'amazon_detail' => array( - 'arguments' => array('item' => array(), 'detail' => NULL), + 'variables' => array('item' => array(), 'detail' => NULL), 'template' => 'amazon-item-detail', 'preprocess functions' => array('amazon_preprocess_amazon_item'), ), @@ -103,13 +101,12 @@ function amazon_theme() { /** * hook_preprocess: amazon_item. */ -function amazon_preprocess_amazon_item(&$variables) { +function amazon_preprocess_amazon_item(&$variables, $theme_type) { $item = $variables['item']; - // Do a quick cycle through the simple keys on the item, check_plain() them, // and stick them in the variables collection. - foreach($item as $key => $value) { + foreach ($item as $key => $value) { if (is_string($value)) { $variables[$key] = filter_xss($value); } @@ -117,10 +114,25 @@ function amazon_preprocess_amazon_item(&$variables) { $variables['type'] = _amazon_clean_type($item['producttypename']); $variables['detailpageurl'] = check_url($item['detailpageurl']); - $variables['editorialreview'] = !empty($item['editorialreviews']) ? check_markup($item['editorialreviews'][0]['content']) : ''; - $variables['customerreview'] = !empty($item['customerreviews']) ? check_markup($item['customerreviews'][0]['content']) : ''; + $variables['editorialreview'] = !empty($item['editorialreviews']) ? filter_xss($item['editorialreviews'][0]['content']) : ''; + if (!empty($item['customerreviews'])) { + foreach ($item['customerreviews'] as &$review) { + $review['content'] = filter_xss($review['content']); + $review['summary'] = filter_xss($review['summary']); + } + } + $variables['customerreview'] = !empty($item['customerreviews']) ? filter_xss($item['customerreviews'][0]['content']) : ''; $variables['invalid_asin'] = !empty($item['invalid_asin']) ? 1 : 0; + $variables['detailpageurl'] = check_url($variables['detailpageurl']); + + if (!empty($variables['customerreviews'])) { + foreach($variables['customerreviews'] as $key => $review) { + $variables['customerreviews'][$key] = filter_xss($variables['customerreviews'][$key]); + } + } + $variables['invalid_asin'] = !empty($variables['invalid_asin']) ? 1 : 0; + if (!empty($variables['theatricalreleasedate'])) { $date = explode('-', $variables['theatricalreleasedate']); $variables['releaseyear'] = $date[0]; @@ -142,7 +154,7 @@ function amazon_preprocess_amazon_item(&$variables) { $variables['participants'] = filter_xss(filter_xss(implode(', ', $item['participants']))); $participant_types = split(',', AMAZON_PARTICIPANT_TYPES); - foreach($participant_types as $participant_type) { + foreach ($participant_types as $participant_type) { $participant_type = strtolower($participant_type); if (!empty($item[$participant_type])) { if (is_string($item[$participant_type])) { @@ -165,8 +177,8 @@ function amazon_preprocess_amazon_item(&$variables) { // Handle supported image resolutions. if (isset($item['imagesets'])) { - foreach($item['imagesets'] as $key => $image) { - $variables[$key] = theme('image', $image['url'], t('Image of') . ' ' . check_plain($item['title']), check_plain($item['title']), array('height' => $image['height'], 'width' => $image['width']), FALSE); + foreach ($item['imagesets'] as $key => $image) { + $variables[$key] = theme('image', array('path' => $image['url'], 'alt' => t('Image of') . ' ' . check_markup($item['title']), 'title' => check_markup($item['title']), 'attributes' => array('height' => $image['height'], 'width' => $image['width']), 'getsize' => FALSE)); $variables["{$key}url"] = check_url($image['url']); $variables["{$key}height"] = check_plain($image['height']); $variables["{$key}width"] = check_plain($image['width']); @@ -174,13 +186,19 @@ function amazon_preprocess_amazon_item(&$variables) { } $variables['image'] = !empty($variables['mediumimage']) ? $variables['mediumimage'] : ''; + $variables['attributes_array'] = array(); + $variables['title_attributes_array'] = array(); + $variables['content_attributes_array'] = array(); + if (!empty($variables['detail']) && $theme_type == 'amazon_detail') { + $variables['classes_array'] = array("amazon-item", "amazon-item-detail-{$variables['detail']}"); + } if (!empty($variables['style'])) { $variables['classes'] = _amazon_item_classes($item) . ' amazon-item-' . check_plain($variables['style']); // A set of more specific templates to use when displaying items. $variables['template_files'][] = 'amazon-item-' . $variables['style']; $variables['template_files'][] = 'amazon-item-' . strtolower($variables['type']); - $variables['template_files'][] = 'amazon-item-' . strtolower($variables['type']) .'-'. $variables['style']; + $variables['template_files'][] = 'amazon-item-' . strtolower($variables['type']) . '-' . $variables['style']; if (!empty($item['view']) && !empty($item['view']->name)) { $vars['template_files'][] = 'amazon-item-view-' . $item['view']->name; @@ -196,7 +214,7 @@ function _amazon_clean_type($type) { } function _amazon_item_classes($item) { - return 'amazon-item amazon-item-'. str_replace('_', '-', _amazon_clean_type($item['producttypename'])); + return 'amazon-item amazon-item-' . str_replace('_', '-', _amazon_clean_type($item['producttypename'])); } @@ -223,37 +241,37 @@ function amazon_http_request($operation, $parameters = array(), $locale = NULL) if (!empty($parameters_after_hook)) { $parameters = $parameters_after_hook; } - $parameters += array('Timestamp' => gmdate("Y-m-d\TH:i:s"). 'Z'); + $parameters += array('Timestamp' => gmdate("Y-m-d\TH:i:s") . 'Z'); uksort($parameters, 'strnatcmp'); $params = array(); - foreach($parameters as $key => $value) { + foreach ($parameters as $key => $value) { if (is_array($value)) { $value = implode(',', $value); } $param = str_replace("%7E", "~", rawurlencode($key)); $value = str_replace("%7E", "~", rawurlencode($value)); - $params[] = $param .'='. $value; + $params[] = $param . '=' . $value; } - $secret_access_key=variable_get('amazon_aws_secret_access_key',""); + $secret_access_key = variable_get('amazon_aws_secret_access_key', ""); if ($secret_access_key == "") { - watchdog('amazon',"No Secret Access Key configured. You must configure one at Admin->Settings->Amazon API",NULL,'error'); + watchdog('amazon', "No Secret Access Key configured. You must configure one at Admin->Settings->Amazon API", NULL, 'error'); drupal_set_message(t("Amazon Module: No Secret Access Key is configured. Please contact your site administrator")); return FALSE; } // Thanks for signature creation code from http://mierendo.com/software/aws_signed_query/ - $query_string = implode('&',$params); + $query_string = implode('&', $params); $parsed_url = parse_url($locale_data['url']); - $host=strtolower($parsed_url['host']); - $string_to_sign="GET\n$host\n{$parsed_url['path']}\n$query_string"; + $host = strtolower($parsed_url['host']); + $string_to_sign = "GET\n$host\n{$parsed_url['path']}\n$query_string"; $signature = base64_encode(hash_hmac('sha256', $string_to_sign, $secret_access_key, TRUE)); $signature = str_replace("%7E", "~", rawurlencode($signature)); $query_string .= "&Signature=$signature"; - $url = $locale_data['url'] .'?'. $query_string; + $url = $locale_data['url'] . '?' . $query_string; // Make the request and return a SimpleXML object. - $results = drupal_http_request($url, array(), 'GET'); + $results = drupal_http_request($url, array('method' => 'GET')); if ($results->code == 200) { $xml = new SimpleXMLElement($results->data); return $xml; @@ -261,11 +279,12 @@ function amazon_http_request($operation, $parameters = array(), $locale = NULL) if ($results->code >= 400 && $results->code < 500) { try { $xml = new SimpleXMLElement($results->data); - } catch (Exception $e) { - watchdog('amazon', "Error handling results: http_code=%http_code, data=%data.",array('%http_code' => $results->code, '%data' => (string)$results->data) ); + } + catch (Exception $e) { + watchdog('amazon', "Error handling results: http_code=%http_code, data=%data.", array('%http_code' => $results->code, '%data' => (string) $results->data) ); return FALSE; } - watchdog('amazon', "HTTP code %http_code accessing Amazon's AWS service: %code, %message", array('%http_code' => $results->code, '%code' => (string)$xml->Error->Code, '%message' => (string)$xml->Error->Message)); + watchdog('amazon', "HTTP code %http_code accessing Amazon's AWS service: %code, %message", array('%http_code' => $results->code, '%code' => (string) $xml->Error->Code, '%message' => (string) $xml->Error->Message)); return FALSE; } watchdog('amazon', "Error accessing Amazon AWS web service. HTTP result code=%code, error=%error", array('%code' => $results->code, '%error' => $results->error)); @@ -315,10 +334,10 @@ function amazon_item_lookup($item_ids = array(), $force_lookup = FALSE) { * Array of cleaned XML structures keyed by ASIN. */ function amazon_item_lookup_from_web($item_ids = array()) { - $amazon_limit = 10; // Amazon will accept no more than 10 items + $amazon_limit = 10; // Amazon will accept no more than 10 items $asins = array(); $results = array(); - $item_ids = array_filter($item_ids); // Remove any empty items. + $item_ids = array_filter($item_ids); // Remove any empty items. foreach ($item_ids as $asin) { if (!empty($asin)) { $asins[] = $asin; @@ -348,22 +367,30 @@ function _amazon_item_batch_lookup_from_web($item_ids = array()) { ); $results = amazon_http_request('ItemLookup', $params); if (!empty($results->Items->Request->Errors)) { - foreach($results->Items->Request->Errors->Error as $error) { - $code = (string)$error->Code; - $message = (string)$error->Message; + foreach ($results->Items->Request->Errors->Error as $error) { + $code = (string) $error->Code; + $message = (string) $error->Message; $matches = array(); // Find and extract the failing ASIN, so we can mark it in the db. if (preg_match('/^([^ ]+) is not a valid value for ItemId/', $message, $matches)) { $error_asin = $matches[1]; - $query = "update {amazon_item} set invalid_asin = TRUE where asin = '%s'"; - db_query($query, $error_asin); + try { + $result = db_update('amazon_item') + ->fields(array('invalid_asin' => TRUE)) + ->condition('asin', $error_asin) + ->execute(); + } + catch(Exception $e) { + amazon_db_error_watchdog('Failed to update invalid_asin=TRUE on amazon_item.', $e); + } + } - watchdog('amazon','Error retrieving Amazon item %code, message: %message.', array('%code' => $code, '%message' => $message), WATCHDOG_WARNING); + watchdog('amazon', 'Error retrieving Amazon item %code, message: %message.', array('%code' => $code, '%message' => $message), WATCHDOG_WARNING); } } $items = array(); if (!empty($results->Items->Item)) { - foreach($results->Items->Item as $xml) { + foreach ($results->Items->Item as $xml) { $item = amazon_item_clean_xml($xml); amazon_item_insert($item); $items["{$item['asin']}"] = $item; @@ -383,12 +410,12 @@ function _amazon_item_batch_lookup_from_web($item_ids = array()) { */ function amazon_item_lookup_from_db($item_ids = array()) { if (!empty($item_ids)) { - $sql = "SELECT * FROM {amazon_item} ai WHERE ai.asin IN ("; - $sql .= implode(',', array_fill(0, count($item_ids), "'%s'")) .') '; - $sql .= 'AND ai.timestamp > %d'; - $results = db_query($sql, $item_ids, time() - variable_get('amazon_refresh_schedule', 86400)); + $timestamp = REQUEST_TIME - variable_get('amazon_refresh_schedule', 86400); + $result = db_query('SELECT * from {amazon_item} WHERE asin IN (:asins) AND timestamp > :timestamp', + array('asins' => $item_ids, 'timestamp' => $timestamp), + array('fetch' => PDO::FETCH_ASSOC)); $items = array(); - while ($item = db_fetch_array($results)) { + foreach ($result as $item) { _amazon_load_child_data($item); $item += module_invoke_all('amazon_item_load', $item); $items["{$item['asin']}"] = $item; @@ -404,24 +431,38 @@ function amazon_item_lookup_from_db($item_ids = array()) { * Amazon data structure. */ function _amazon_load_child_data(&$item) { - $result = db_query("SELECT type, participant FROM {amazon_item_participant} WHERE asin = '%s'", $item['asin']); - while ($participant = db_fetch_array($result)) { + $result = db_query('SELECT type, participant FROM {amazon_item_participant} WHERE asin = :asin', + array('asin' => $item['asin']), + array('fetch' => PDO::FETCH_ASSOC)); + foreach ($result as $participant) { unset($participant['asin']); $item[$participant['type']][] = $participant['participant']; $item['participants'][] = $participant['participant']; } - $result = db_query("SELECT * FROM {amazon_item_image} WHERE asin = '%s'", $item['asin']); - while ($image = db_fetch_array($result)) { + $result = db_query('SELECT * FROM {amazon_item_image} WHERE asin = :asin', + array('asin' => $item['asin']), + array('fetch' => PDO::FETCH_ASSOC)); + foreach ($result as $image) { unset($image['asin']); $item['imagesets'][$image['size']] = $image; } - $result = db_query("SELECT * FROM {amazon_item_editorial_review} WHERE asin = '%s'", $item['asin']); - while ($review = db_fetch_array($result)) { + $result = db_query('SELECT * FROM {amazon_item_editorial_review} WHERE asin = :asin', + array('asin' => $item['asin']), + array('fetch' => PDO::FETCH_ASSOC)); + foreach ($result as $review) { unset($review['asin']); $item['editorialreviews'][] = $review; } + $result = db_query('SELECT * FROM {amazon_item_customer_review} WHERE asin = :asin', + array('asin' => $item['asin']), + array('fetch' => PDO::FETCH_ASSOC)); + foreach ($result as $review) { + unset($review['asin']); + $item['customerreviews'][] = $review; + } + } /** @@ -435,41 +476,40 @@ function _amazon_load_child_data(&$item) { function amazon_item_clean_xml($xml) { $metadata = amazon_data_cache(); $item = array(); - // Pull the absolute basic information Amazon keeps at the top level // of the XML tree, cast to string, and move on. - $item['asin'] = (string)$xml->ASIN; + $item['asin'] = (string) $xml->ASIN; if (empty($item['isbn'])) { - $item['isbn'] = (string)$xml->ItemAttributes->ISBN; + $item['isbn'] = (string) $xml->ItemAttributes->ISBN; } if (empty($item['ean'])) { - $item['ean'] = (string)$xml->ItemAttributes->EAN; + $item['ean'] = (string) $xml->ItemAttributes->EAN; } - $item['salesrank'] = (string)$xml->SalesRank; - $item['detailpageurl'] = (string)$xml->DetailPageURL; + $item['salesrank'] = (string) $xml->SalesRank; + $item['detailpageurl'] = (string) $xml->DetailPageURL; if (!empty($xml->ItemAttributes->ListPrice)) { - $item['listpriceamount'] = (string)$xml->ItemAttributes->ListPrice->Amount; - $item['listpricecurrencycode'] = (string)$xml->ItemAttributes->ListPrice->CurrencyCode; - $item['listpriceformattedprice'] = (string)$xml->ItemAttributes->ListPrice->FormattedPrice; + $item['listpriceamount'] = (string) $xml->ItemAttributes->ListPrice->Amount; + $item['listpricecurrencycode'] = (string) $xml->ItemAttributes->ListPrice->CurrencyCode; + $item['listpriceformattedprice'] = (string) $xml->ItemAttributes->ListPrice->FormattedPrice; } if (!empty($xml->OfferSummary->LowestNewPrice)) { - $item['lowestpriceamount'] = (string)$xml->OfferSummary->LowestNewPrice->Amount; - $item['lowestpricecurrencycode'] = (string)$xml->OfferSummary->LowestNewPrice->CurrencyCode; - $item['lowestpriceformattedprice'] = (string)$xml->OfferSummary->LowestNewPrice->FormattedPrice; + $item['lowestpriceamount'] = (string) $xml->OfferSummary->LowestNewPrice->Amount; + $item['lowestpricecurrencycode'] = (string) $xml->OfferSummary->LowestNewPrice->CurrencyCode; + $item['lowestpriceformattedprice'] = (string) $xml->OfferSummary->LowestNewPrice->FormattedPrice; } // Note that this one assumes we've searched with Merchant = Amazon. // Otherwise we can do an xpath search looking for the actual amazon listing. - if (!empty($xml->Offers->Offer[0]->OfferListing->Price) && (string)$xml->Offers->Offer[0]->Merchant->MerchantId == 'ATVPDKIKX0DER') { - $item['amazonpriceamount'] = (string)$xml->Offers->Offer[0]->OfferListing->Price->Amount; - $item['amazonpricecurrencycode'] = (string)$xml->Offers->Offer[0]->OfferListing->Price->CurrencyCode; - $item['amazonpriceformattedprice'] = (string)$xml->Offers->Offer[0]->OfferListing->Price->FormattedPrice; + if (!empty($xml->Offers->Offer[0]->OfferListing->Price) && (string) $xml->Offers->Offer[0]->Merchant->MerchantId == 'ATVPDKIKX0DER') { + $item['amazonpriceamount'] = (string) $xml->Offers->Offer[0]->OfferListing->Price->Amount; + $item['amazonpricecurrencycode'] = (string) $xml->Offers->Offer[0]->OfferListing->Price->CurrencyCode; + $item['amazonpriceformattedprice'] = (string) $xml->Offers->Offer[0]->OfferListing->Price->FormattedPrice; } $participant_types = split(',', AMAZON_PARTICIPANT_TYPES); // Pull in the basics of the ItemAttributes collection. - foreach((array)($xml->ItemAttributes) as $key => $value) { + foreach ((array) ($xml->ItemAttributes) as $key => $value) { if (is_string($value) && !in_array($key, $participant_types)) { $key = strtolower($key); $item[$key] = $value; @@ -479,9 +519,9 @@ function amazon_item_clean_xml($xml) { // Handle the Authors/Artists/Etc. foreach ($participant_types as $key) { if (isset($xml->ItemAttributes->$key)) { - foreach($xml->ItemAttributes->$key as $value) { - $item[strtolower($key)][] = (string)$value; - $item['participants'][] = (string)$value; + foreach ($xml->ItemAttributes->$key as $value) { + $item[strtolower($key)][] = (string) $value; + $item['participants'][] = (string) $value; } } } @@ -491,12 +531,12 @@ function amazon_item_clean_xml($xml) { // and ignore the rest for now. $supported_sizes = split(',', AMAZON_IMAGE_SIZES); if (isset($xml->ImageSets->ImageSet)) { - foreach((array)$xml->ImageSets->ImageSet as $key => $data) { + foreach ((array) $xml->ImageSets->ImageSet as $key => $data) { if (in_array($key, $supported_sizes)) { $item['imagesets'][strtolower($key)] = array( - 'url' => (string)$data->URL, - 'height' => (string)$data->Height, - 'width' => (string)$data->Width, + 'url' => (string) $data->URL, + 'height' => (string) $data->Height, + 'width' => (string) $data->Width, ); } } @@ -504,22 +544,22 @@ function amazon_item_clean_xml($xml) { // Handle the editorial reviews. if (isset($xml->EditorialReviews)) { - foreach($xml->EditorialReviews->EditorialReview as $data) { + foreach ($xml->EditorialReviews->EditorialReview as $data) { $item['editorialreviews'][] = array( - 'source' => (string)$data->Source, - 'content' => (string)$data->Content, + 'source' => (string) $data->Source, + 'content' => (string) $data->Content, ); } } // And the customer reviews. if (isset($xml->CustomerReviews)) { - foreach($xml->CustomerReviews->Review as $data) { + foreach ($xml->CustomerReviews->Review as $data) { $item['customerreviews'][] = array( - 'rating' => (string)$data->Rating, - 'date' => (string)$data->Date, - 'summary' => (string)$data->Summary, - 'content' => (string)$data->Content, + 'rating' => (string) $data->Rating, + 'date' => (string) $data->Date, + 'summary' => (string) $data->Summary, + 'content' => (string) $data->Content, ); } } @@ -528,7 +568,7 @@ function amazon_item_clean_xml($xml) { // that would otherwise be ignored. We can't use module_invoke_all, as it // would lose the reference. foreach (module_implements('amazon_item_clean_xml') as $module) { - $function = $module .'_amazon_item_clean_xml'; + $function = $module . '_amazon_item_clean_xml'; $function($item, $xml); } return $item; @@ -542,24 +582,48 @@ function amazon_item_clean_xml($xml) { * No return value. */ function amazon_item_insert($item) { + static $item_keys = NULL; + if (empty($item_keys)) { + require_once('amazon.install'); + $schema = amazon_schema(); + $item_keys = $schema['amazon_item']['fields']; + } // We have boatloads of data to insert in here, so we're going to // cheat and blow away the old entries first. amazon_item_delete($item['asin']); $metadata = amazon_data_cache(); - $item['timestamp'] = time(); - drupal_write_record('amazon_item', $item); + $item['timestamp'] = REQUEST_TIME; + + // The db_insert needs fields that match exactly to the database, + // so we'll intersect with what the actual schema says. + $db_item = array_intersect_key($item, $item_keys); + try { + db_insert('amazon_item') + ->fields($db_item) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon_item table", $e); + } // Handle the various credits for a product, including Artist, Author, // Actor, etc. We map these to a separate table. if (in_array('creators', variable_get('amazon_core_data', array('creators', 'images')))) { $participant_types = split(',', AMAZON_PARTICIPANT_TYPES); foreach ($participant_types as $type) { - if (isset($item[strtolower($type)])){ - foreach((array)$item[strtolower($type)] as $participant) { + if (isset($item[strtolower($type)])) { + foreach ((array) $item[strtolower($type)] as $participant) { $item_participant = array('asin' => $item['asin'], 'type' => strtolower($type), 'participant' => $participant); - drupal_write_record('amazon_item_participant', $item_participant); + try { + db_insert('amazon_item_participant') + ->fields($item_participant) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon_item_participant table", $e); + } } } } @@ -568,9 +632,16 @@ function amazon_item_insert($item) { // Save the product images if they exist. if (in_array('images', variable_get('amazon_core_data', array('creators', 'images')))) { if (isset($item['imagesets'])) { - foreach($item['imagesets'] as $size => $data) { + foreach ($item['imagesets'] as $size => $data) { $image = array('asin' => $item['asin'], 'size' => $size, 'height' => $data['height'], 'width' => $data['width'], 'url' => $data['url']); - drupal_write_record('amazon_item_image', $image); + try { + db_insert('amazon_item_image') + ->fields($image) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon_item_image table", $e); + } } } } @@ -578,18 +649,33 @@ function amazon_item_insert($item) { // Save the editorial reviews if they exist. if (in_array('editorial_reviews', variable_get('amazon_core_data', array('creators', 'images')))) { if (isset($item['editorialreviews'])) { - foreach($item['editorialreviews'] as $data) { + foreach ($item['editorialreviews'] as $data) { $review = array('asin' => $item['asin'], 'source' => $data['source'], 'content' => $data['content']); - drupal_write_record('amazon_item_editorial_review', $review); + try { + db_insert('amazon_item_editorial_review') + ->fields($review) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon_item_editorial_review table", $e); + } } } } // Save the customer reviews if they exist. if (in_array('customer_reviews', variable_get('amazon_core_data', array('creators', 'images')))) { if (isset($item['customerreviews'])) { - foreach($item['customerreviews'] as $data) { + foreach ($item['customerreviews'] as $data) { $review = array('asin' => $item['asin'], 'rating' => $data['rating'], 'date' => $data['date'], 'summary' => $data['summary'], 'content' => $data['content']); - drupal_write_record('amazon_item_customer_review', $review); + try { + db_insert('amazon_item_customer_review') + ->fields($review) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon_item_editorial_review table", $e); + } + } } } @@ -605,11 +691,21 @@ function amazon_item_insert($item) { */ function amazon_item_delete($asin) { module_invoke_all('amazon_item_delete', $asin); - db_query("DELETE FROM {amazon_item} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_item_participant} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_item_image} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_item_editorial_review} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_item_customer_review} WHERE asin = '%s'", $asin); + db_delete('amazon_item') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_item_participant') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_item_image') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_item_editorial_review') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_item_customer_review') + ->condition('asin', $asin) + ->execute(); } /** @@ -623,7 +719,7 @@ function amazon_item_delete($asin) { * after removing dashes. */ function amazon_convert_to_asin($input) { - $input = preg_replace('/-/','',$input); // Remove dashes. + $input = preg_replace('/-/', '', $input); // Remove dashes. if (preg_match('/^https?:/', $input)) { $parts = preg_split('/\//', $input); $asin = $parts[5]; // 6th section of split, right after /dp/ @@ -654,7 +750,7 @@ function amazon_ean_to_asin($ean) { ); $results = amazon_http_request('ItemLookup', $params); if (!empty($results->Items->Item->ASIN)) { - $asin = (string)$results->Items->Item->ASIN; + $asin = (string) $results->Items->Item->ASIN; } return $asin; } @@ -664,30 +760,34 @@ function amazon_ean_to_asin($ean) { function amazon_item_node_save($asin, $node, $module = 'amazon', $weight = 0) { amazon_item_node_delete($asin, $nid, $module); - db_query("INSERT INTO {amazon_item_node} (asin, vid, nid, module, weight) VALUES ('%s', %d, '%s', %d)", $asin, $nid, $module, $weight); + try { + $id = db_insert('amazon_item_node') + ->fields(array( + 'asin' => $asin, + 'nid' => $nid, + 'module' => $module, + 'weight' => $weight, + )) + ->execute(); + } catch(Exception $e) { + amazon_db_error_watchdog('Failed to save amazon_item_node.', $e); + } } function amazon_item_node_delete($asin = NULL, $nid = NULL, $module = NULL) { - $sql = "DELETE FROM {amazon_item_node} WHERE 1 = 1"; - $params = array(); + $delete = db_delete('amazon_item_node'); if (isset($asin)) { - $sql = " AND asin = '%s'"; - $params[] = $asin; + $delete = $delete->condition('asin', $asin); } if (isset($nid)) { - $sql = " AND nid = %d"; - $params[] = $nid; + $delete = $delete->condition('nid', $nid); } if (isset($module)) { - $sql = " AND module = '%s'"; - $params[] = $module; - } - - if (count($params)) { - db_query($sql, $params); + $delete = $delete->condition('module', $module); } + $delete->execute(); } @@ -759,14 +859,14 @@ function amazon_get_associate_id() { function amazon_cron() { // Here, we're going to chug through all the existing ASINs and update them. // We'll grab 50 at a time to avoid thrashing things. - $sql = "SELECT asin FROM {amazon_item} WHERE timestamp < %d"; - $result = db_query_range($sql, time() - variable_get('amazon_refresh_schedule', 86400), 0, 50); - $asins = array(); - - while($item = db_fetch_array($result)) { - $asins[] = $item['asin']; - } - + $per_cron_limit = 50; + $needs_update_time = REQUEST_TIME - variable_get('amazon_refresh_schedule', 86400); + $result = db_select('amazon_item', NULL, array('fetch' => PDO::FETCH_ASSOC)) + ->fields('amazon_item', array('asin')) + ->condition('timestamp', $needs_update_time, '<') + ->range(0, $per_cron_limit) + ->execute(); + $asins = $result->FetchCol(); if (!empty($asins)) { if ($items = amazon_item_lookup_from_web($asins)) { foreach ($items as $item) { @@ -780,6 +880,7 @@ function amazon_cron() { } } +//D6FIX: hook_token_info function amazon_token_list($type = 'all') { if ($type == 'amazon_item' || $type == 'all') { $tokens['amazon_item']['asin'] = t('Product ID'); @@ -802,9 +903,10 @@ function amazon_token_list($type = 'all') { } } +//D6FIX: hook_tokens() function amazon_token_values($type, $object = NULL, $options = array()) { if ($type == 'amazon_item' || $type == 'all') { - $item = (array)$object; + $item = (array) $object; $values['asin'] = check_plain($item['asin']); $values['isbn'] = check_plain($item['isbn']); $values['ean'] = check_plain($item['ean']); @@ -851,10 +953,10 @@ function template_preprocess_amazon_views_view_row_item(&$vars) { $item['view'] = $vars['view']; $vars['amazon_item'] = $item; if ($options['display_format'] == 'inline') { - $vars['content'] = theme('amazon_item_inline', $item, $options['display_format']); + $vars['content'] = theme('amazon_item_inline', array('item' => $item, 'style' => $options['display_format'])); } else { - $vars['content'] = theme('amazon_item', $item, $options['display_format']); + $vars['content'] = theme('amazon_item', array('item' => $item, 'style' => $options['display_format'])); } } } @@ -862,3 +964,18 @@ function template_preprocess_amazon_views_view_row_item(&$vars) { function amazon_init() { drupal_add_css(drupal_get_path('module', 'amazon') . '/amazon.css'); } + +/** + * Have watchdog emit complete errors about a database exception. + * + * @param $msg + * The message explaining the error. + * The message should not be localized, as it will be passed to watchdog(). + * @param $e + * The exception which was caught + * + */ +function amazon_db_error_watchdog($msg, $e) { + watchdog('amazon', "$msg: Message = %message, query= %query", + array('%message' => $e->getMessage(), '%query' => $e->query_string)); +} \ No newline at end of file diff --git amazon_examples/amazon_examples.defaults.inc amazon_examples/amazon_examples.defaults.inc deleted file mode 100644 index 1f57c07..0000000 --- amazon_examples/amazon_examples.defaults.inc +++ /dev/null @@ -1,66 +0,0 @@ - 'field_asin', - 'type_name' => 'amazon_example', - 'display_settings' => array( - 'label' => array( - 'format' => 'above', - 'exclude' => 0, - ), - 'teaser' => array( - 'format' => 'default', - 'exclude' => 0, - ), - 'full' => array( - 'format' => 'default', - 'exclude' => 0, - ), - '4' => array( - 'format' => 'default', - 'exclude' => 0, - ), - '2' => array( - 'format' => 'default', - 'exclude' => 0, - ), - '3' => array( - 'format' => 'default', - 'exclude' => 0, - ), - ), - 'widget_active' => '1', - 'type' => 'asin', - 'required' => '1', - 'multiple' => '0', - 'module' => 'asin', - 'active' => '1', - 'widget' => array( - 'default_value' => array( - '0' => array( - 'asin' => '', - ), - ), - 'default_value_php' => NULL, - 'label' => 'ASIN', - 'weight' => '-4', - 'description' => 'Enter a 10-digit ASIN that identifies an Amazon item. ', - 'type' => 'asin_text', - 'module' => 'asin', - ), - ); - - // Translatables - array( - t('ASIN'), - ); - - return $fields; -} diff --git amazon_examples/amazon_examples.features.inc amazon_examples/amazon_examples.features.inc deleted file mode 100644 index 65d3f87..0000000 --- amazon_examples/amazon_examples.features.inc +++ /dev/null @@ -1,28 +0,0 @@ - array( - 'name' => t('Amazon Example'), - 'module' => 'features', - 'description' => t('This is just an example content type to show how Amazon module can be used with CCK fields. A single CCK field is provided. You can populate a few nodes and then see how views work and how these are displayed. A sample view that uses this CCK type is provided.'), - 'has_title' => '1', - 'title_label' => t('Title'), - 'has_body' => '0', - 'body_label' => '', - 'min_word_count' => '0', - 'help' => '', - ), - ); - return $items; -} diff --git amazon_examples/amazon_examples.features.views.inc amazon_examples/amazon_examples.features.views.inc deleted file mode 100644 index 3f5dc9d..0000000 --- amazon_examples/amazon_examples.features.views.inc +++ /dev/null @@ -1,291 +0,0 @@ -name = 'amazon_example_view'; - $view->description = 'Amazon Example View'; - $view->tag = 'examples'; - $view->view_php = ''; - $view->base_table = 'node'; - $view->is_cacheable = FALSE; - $view->api_version = 2; - $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */ - $handler = $view->new_display('default', 'Defaults', 'default'); - $handler->override_option('relationships', array( - 'field_asin_asin' => array( - 'label' => 'field_asin_asin', - 'required' => 1, - 'id' => 'field_asin_asin', - 'table' => 'node_data_field_asin', - 'field' => 'field_asin_asin', - 'relationship' => 'none', - ), - )); - $handler->override_option('fields', array( - 'nid' => array( - 'id' => 'nid', - 'table' => 'node', - 'field' => 'nid', - ), - 'asin' => array( - 'label' => 'ASIN', - 'alter' => array( - 'alter_text' => 0, - 'text' => '', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'exclude' => 0, - 'id' => 'asin', - 'table' => 'amazon_item', - 'field' => 'asin', - 'relationship' => 'field_asin_asin', - ), - 'title' => array( - 'label' => 'Title', - 'alter' => array( - 'alter_text' => 0, - 'text' => '', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'link_format' => 'plain', - 'exclude' => 0, - 'id' => 'title', - 'table' => 'amazon_item', - 'field' => 'title', - 'relationship' => 'field_asin_asin', - ), - 'detailpageurl' => array( - 'label' => 'Detail page URL', - 'alter' => array( - 'alter_text' => 0, - 'text' => '', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'exclude' => 1, - 'id' => 'detailpageurl', - 'table' => 'amazon_item', - 'field' => 'detailpageurl', - 'relationship' => 'field_asin_asin', - 'override' => array( - 'button' => 'Override', - ), - ), - 'listpriceformattedprice' => array( - 'id' => 'listpriceformattedprice', - 'table' => 'amazon_item', - 'field' => 'listpriceformattedprice', - ), - 'publisher' => array( - 'id' => 'publisher', - 'table' => 'amazon_item', - 'field' => 'publisher', - ), - 'publicationdate' => array( - 'label' => 'Publication date', - 'alter' => array( - 'alter_text' => 0, - 'text' => '', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'date_format' => 'default', - 'custom_date_format' => '', - 'exclude' => 0, - 'id' => 'publicationdate', - 'table' => 'amazon_book', - 'field' => 'publicationdate', - 'relationship' => 'field_asin_asin', - ), - 'product_image' => array( - 'label' => 'Image URL', - 'alter' => array( - 'alter_text' => 0, - 'text' => '', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'image_size' => 'mediumimage', - 'link_format' => 'plain', - 'exclude' => 1, - 'id' => 'product_image', - 'table' => 'amazon_item_image', - 'field' => 'product_image', - 'relationship' => 'field_asin_asin', - 'presentation_format' => 'plain_url', - ), - 'nothing' => array( - 'label' => 'Custom: Example Link to Image', - 'alter' => array( - 'text' => 'Example link/image: ', - 'make_link' => 0, - 'path' => '', - 'link_class' => '', - 'alt' => '', - 'prefix' => '', - 'suffix' => '', - 'help' => '', - 'trim' => 0, - 'max_length' => '', - 'word_boundary' => 1, - 'ellipsis' => 1, - 'strip_tags' => 0, - 'html' => 0, - ), - 'exclude' => 0, - 'id' => 'nothing', - 'table' => 'views', - 'field' => 'nothing', - 'relationship' => 'none', - ), - )); - $handler->override_option('filters', array( - 'status' => array( - 'operator' => '=', - 'value' => '1', - 'group' => '0', - 'exposed' => FALSE, - 'expose' => array( - 'operator' => FALSE, - 'label' => '', - ), - 'id' => 'status', - 'table' => 'node', - 'field' => 'status', - 'relationship' => 'none', - ), - 'type' => array( - 'operator' => 'in', - 'value' => array( - 'amazon_example' => 'amazon_example', - ), - 'group' => '0', - 'exposed' => FALSE, - 'expose' => array( - 'operator' => FALSE, - 'label' => '', - ), - 'id' => 'type', - 'table' => 'node', - 'field' => 'type', - 'relationship' => 'none', - ), - )); - $handler->override_option('access', array( - 'type' => 'none', - )); - $handler->override_option('cache', array( - 'type' => 'none', - )); - $handler->override_option('header', 'This is an example view that you can experiment with. - -If you see no results, it\'s because you have to create some nodes first. Go to Create Content->Amazon Example and create a node or two. Try using these ASINs: 0596515804, 1430209895, 0470429038.'); - $handler->override_option('header_format', '1'); - $handler->override_option('header_empty', 1); - $handler->override_option('use_ajax', TRUE); - $handler->override_option('use_pager', '1'); - $handler->override_option('style_plugin', 'table'); - $handler->override_option('style_options', array( - 'grouping' => '', - 'override' => 1, - 'sticky' => 0, - 'order' => 'asc', - 'columns' => array( - 'asin' => 'asin', - 'nid' => 'nid', - ), - 'info' => array( - 'asin' => array( - 'sortable' => 0, - 'separator' => '', - ), - 'nid' => array( - 'sortable' => 0, - 'separator' => '', - ), - ), - 'default' => '-1', - )); - $handler = $view->new_display('page', 'Page', 'page_1'); - $handler->override_option('path', 'amazon_example_view'); - $handler->override_option('menu', array( - 'type' => 'normal', - 'title' => 'Amazon Example View', - 'description' => '', - 'weight' => '0', - 'name' => 'navigation', - )); - $handler->override_option('tab_options', array( - 'type' => 'none', - 'title' => '', - 'description' => '', - 'weight' => 0, - )); - - $views[$view->name] = $view; - - return $views; -} diff --git amazon_examples/amazon_examples.info amazon_examples/amazon_examples.info deleted file mode 100644 index a4e5676..0000000 --- amazon_examples/amazon_examples.info +++ /dev/null @@ -1,14 +0,0 @@ -core = "6.x" -dependencies[] = "amazon" -dependencies[] = "amazon_media" -dependencies[] = "asin" -dependencies[] = "features" -dependencies[] = "views" -description = "Provides Amazon module CCK type and view as a demo" -features[content][] = "amazon_example-field_asin" -features[node][] = "amazon_example" -features[views][] = "amazon_example_view" -name = "Amazon Examples" -package = "Amazon" -project = "amazon_examples" -version = "6.x-1.0-beta9" diff --git amazon_examples/amazon_examples.module amazon_examples/amazon_examples.module deleted file mode 100644 index 0ce1b04..0000000 --- amazon_examples/amazon_examples.module +++ /dev/null @@ -1,3 +0,0 @@ -on the Amazon module handbook page.'); - } else { + } + else { return t('Link to Amazon products with: [amazon product_id inline|full|thumbnail|datadescriptor]. Example: [amazon 1590597559 thumbnail] or [amazon 1590597559 author]. Details are on the Amazon module handbook page.'); } } /** - * Implementation of hook_filter(). + * Implements hook_filter_info(). */ -function amazon_filter_filter($op, $delta = 0, $format = -1, $text = '') { - if ($op == 'list') { - return array(0 => t('Amazon filter')); - } - - switch ($delta) { - case 0: - switch ($op) { - case 'description': - return t('Lets writers use the [amazon] tag to embed Amazon product information in text.'); - case 'prepare': - return $text; - case 'process': - return _amazon_filter_process_text($text); - } - break; - } +function amazon_filter_info() { + $filters['amazon'] = array( + 'title' => t('Amazon filter'), + 'description' => t('Provides access to many types of Amazon data. Simplest usage: [amazon ASIN inline], for example [amazon 0596515804 inline].'), + 'process callback' => '_amazon_filter_process_text', + 'tips callback' => '_amazon_filter_tips', + ); + return $filters; } +/** + * Actual filter processing function - changes [amazon ] in text. + * @param $text + * Text to be transformed. + * @return + * The transformed text. + */ function _amazon_filter_process_text($text) { $pattern = "/\[amazon +(.*?)(?: +(.*?))?\]/"; $matches = array(); @@ -71,19 +70,23 @@ function _amazon_filter_process_text($text) { switch ($action) { case "": case 'inline': - $replace[] = theme('amazon_inline_item', $item); + $replace[] = theme('amazon_inline_item', array('item' =>$item)); break; - case 'thumbnail': // Handle themeable cases, like thumbnail, full. + case 'thumbnail': + // Handle themeable cases, like thumbnail, full. case 'full': - $replace[] = theme('amazon_item', $item, $action); + $replace[] = theme('amazon_item', array('item' => $item, 'style' => $action)); break; - default: // Allow to use anything found in the item. - $replace[] = theme('amazon_detail', $item, $action); + default: + // Allow to use anything found in the item. + $replace[] = theme('amazon_detail', array('item' => $item, 'detail' => $action)); break; } - } else { // error case + } + else { + // error case $replace[] = ""; } } diff --git amazon_media/amazon_media.info amazon_media/amazon_media.info index 425206d..e7d0bad 100644 --- amazon_media/amazon_media.info +++ amazon_media/amazon_media.info @@ -2,5 +2,14 @@ name = Amazon media description = Stores extended Amazon product information for books, music, DVDs, and software. package = Amazon dependencies[] = amazon -core = 6.x +core = 7.x php = 5.2 + +files[] = amazon-item-book-details.tpl.php +files[] = amazon-item-dvd-details.tpl.php +files[] = amazon-item-software-details.tpl.php +files[] = amazon-item-video-games-details.tpl.php +files[] = amazon_media.install +files[] = amazon_media.module +files[] = amazon_media.theme.inc +files[] = amazon_media.views.inc diff --git amazon_media/amazon_media.install amazon_media/amazon_media.install index 7471556..9de7d3c 100644 --- amazon_media/amazon_media.install +++ amazon_media/amazon_media.install @@ -1,4 +1,10 @@ 'varchar', 'length' => 64); - db_change_field($ret, 'amazon_dvd', 'audiencerating', 'theatricalreleasedate', $field); - - return $ret; -} - -/** - * Add the isbn and ean fields to a book item. - */ -function amazon_media_update_6002() { - $ret = array(); - db_add_field($ret, 'amazon_book', 'isbn', array('type' => 'varchar', 'length' => 20)); - db_add_field($ret, 'amazon_book', 'ean', array('type' => 'varchar', 'length' => 20)); - return $ret; -} \ No newline at end of file diff --git amazon_media/amazon_media.module amazon_media/amazon_media.module index 5eaec4a..328b993 100644 --- amazon_media/amazon_media.module +++ amazon_media/amazon_media.module @@ -1,21 +1,31 @@ array( - 'arguments' => array('item' => array()), + 'variables' => array('item' => array()), 'file' => 'amazon_media.theme.inc', ), 'amazon_inline_item_software' => array( - 'arguments' => array('item' => array()), + 'variables' => array('item' => array()), 'file' => 'amazon_media.theme.inc', ), 'amazon_inline_item_video_games' => array( - 'arguments' => array('item' => array()), + 'variables' => array('item' => array()), 'file' => 'amazon_media.theme.inc', ), 'amazon_inline_item_console_video_games' => array( - 'arguments' => array('item' => array()), + 'variables' => array('item' => array()), 'function' => 'theme_amazon_inline_item_video_games', 'file' => 'amazon_media.theme.inc', ), @@ -31,7 +41,7 @@ function amazon_media_theme_registry_alter(&$theme_registry) { if (!empty($theme_registry['amazon_item'])) { // We'll try our best to avoid stepping on theme template files. // God, how I hate template inheritance. - if (count($theme_registry['amazon_item']['theme paths']) > 1) { + if (!empty($theme_registry['amazon_item']['theme_paths']) && count($theme_registry['amazon_item']['theme paths']) > 1) { $theme = array_pop($theme_registry['amazon_item']['theme paths']); } $theme_registry['amazon_item']['theme paths'][] = drupal_get_path('module', 'amazon_media'); @@ -41,6 +51,11 @@ function amazon_media_theme_registry_alter(&$theme_registry) { } } +/** + * Implements hook_preprocess. + * + * @param $variables + */ function amazon_media_preprocess_amazon_item(&$variables) { if (!empty($variables['theatricalreleasedate'])) { $date = explode('-', $variables['theatricalreleasedate']); @@ -66,65 +81,91 @@ function amazon_media_preprocess_amazon_item(&$variables) { ); } - +/** + * Load and return additional information for an ASINI item. + * @param $item + * The item requiring additions. + * @return + * The added array elements, as an array. + */ function amazon_media_amazon_item_load($item) { - switch ($item['producttypename']) { - case 'ABIS_BOOK': - $additions = db_fetch_array(db_query("SELECT * FROM {amazon_book} WHERE asin = '%s'", $item['asin'])); - break; - case 'VIDEO_DVD': - case 'ABIS_DVD': - $additions = db_fetch_array(db_query("SELECT * FROM {amazon_dvd} WHERE asin = '%s'", $item['asin'])); - break; - case 'ABIS_MUSIC': - $additions = db_fetch_array(db_query("SELECT * FROM {amazon_music} WHERE asin = '%s'", $item['asin'])); - break; - case 'CONSOLE_VIDEO_GAMES': - case 'VIDEO_GAMES': - case 'SOFTWARE': - $additions = db_fetch_array(db_query("SELECT * FROM {amazon_software} WHERE asin = '%s'", $item['asin'])); - break; - } - if (isset($additions)) { - return $additions; - } + $table = amazon_media_get_table_name($item); + $additions = db_query("SELECT * FROM {$table} WHERE asin = :asin", + array('asin' => $item['asin']))->fetchAssoc(); + return $additions; +} + +/** + * Given an item, return the name of the table it's associated with. + * @param $item + * populated amazon_item with $item['producttypename'] populated. + * @return + * the name of the associated table. + */ +function amazon_media_get_table_name($item) { + static $names = array('ABIS_BOOK' => 'amazon_book', + 'VIDEO_DVD' => 'amazon_dvd', + 'ABIS_DVD' => 'amazon_dvd', + 'ABIS_MUSIC' => 'amazon_music', + 'CONSOLE_VIDEO_GAMES' => 'amazon_software', + 'VIDEO_GAMES' => 'amazon_software', + 'SOFTWARE' => 'amazon_software', + ); + return $names[$item['producttypename']]; } +/** + * Insert the associated information into the related table. + * @param $item + * Populated amazon item record. + */ function amazon_media_amazon_item_insert($item) { - switch ($item['producttypename']) { - case 'ABIS_BOOK': - drupal_write_record('amazon_book', $item); - break; - case 'VIDEO_DVD': - case 'ABIS_DVD': - drupal_write_record('amazon_dvd', $item); - break; - case 'ABIS_MUSIC': - // Often the artist is an array. - if (!empty($item['artist']) && is_array($item['artist'])) { - $item['artist'] = join(",", $item['artist']); - } - drupal_write_record('amazon_music', $item); - break; - case 'CONSOLE_VIDEO_GAMES': - case 'VIDEO_GAMES': - case 'SOFTWARE': - drupal_write_record('amazon_software', $item); - break; + static $item_keys = NULL; + if (empty($item_keys)) { + require_once('amazon_media.install'); + $schema = amazon_media_schema(); + $item_keys = $schema; + } + $table = amazon_media_get_table_name($item); + + // We need to present a record that only has the items in it used by + // this table. + $db_item = array_intersect_key($item, $item_keys[$table]['fields']); + + try { + db_insert($table) + ->fields($db_item) + ->execute(); + } + catch (Exception $e) { + amazon_db_error_watchdog("Failed to insert item into amazon table", $e); } } +/** + * Delete a record using the asin as key. + * @param $asin + * the asin to delete. + */ function amazon_media_amazon_item_delete($asin) { // This is pretty inefficient; we're going to thrash these tables // every time a product gets deleted or updated. We'll solve it later. - db_query("DELETE FROM {amazon_book} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_dvd} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_music} WHERE asin = '%s'", $asin); - db_query("DELETE FROM {amazon_software} WHERE asin = '%s'", $asin); + db_delete('amazon_book') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_dvd') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_music') + ->condition('asin', $asin) + ->execute(); + db_delete('amazon_software') + ->condition('asin', $asin) + ->execute(); } /** - * Implementation of hook_views_api. + * Implements hook_views_api. */ function amazon_media_views_api() { return array('api' => 2); diff --git amazon_media/amazon_media.theme.inc amazon_media/amazon_media.theme.inc index 782b32d..25dffef 100644 --- amazon_media/amazon_media.theme.inc +++ amazon_media/amazon_media.theme.inc @@ -1,36 +1,54 @@ '; - $output .= theme('image', $item['imagesets']['mediumimage']['url'], t('Cover image'), check_markup($item['title']), NULL, FALSE); - $output .= '

'. l(check_plain($item['title']), $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))) .'

'; + $output .= '
'; + $output .= theme('image', array('path' => $item['imagesets']['mediumimage']['url'], 'alt' => t('Cover image'), 'title' => check_markup($item['title']), 'attributes' => array(), 'getsize' => FALSE)); + $output .= '

' . l(check_plain($item['title']), $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))) . '

'; $output .= '
'; break; case 'thumbnail': - $output .= '
'; - $output .= theme('image', $item['imagesets']['mediumimage']['url'], t('Cover image'), check_markup($item['title']), NULL, FALSE); + $output .= '
'; + $output .= theme('image', array('path' => $item['imagesets']['mediumimage']['url'], 'alt' => t('Cover image'), 'title' => check_markup($item['title']), 'attributes' => array(), 'getsize' => FALSE)); $output .= '
'; break; default: - $output .= '
'; - $output .= theme('image', $item['imagesets']['smallimage']['url'], t('Cover image'), check_markup($item['title']), NULL, FALSE); + $output .= '
'; + $output .= theme('image', array('path' => $item['imagesets']['smallimage']['url'], 'alt' => t('Cover image'), 'title' => check_markup($item['title']), 'attributes' => array(), 'getsize' => FALSE)); $date = split('-', $item['theatricalreleasedate']); - $output .= '

'. l(check_markup($item['title']), $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))) .' ('. check_plain($date[0]) .')

'; - $output .= '
'. t('Director') .': '. implode(', ', $item['director']) .'
'; - $output .= '
'. t('Rating') .': '. $item['audiencerating'] .'
'; - $output .= '
'. t('Running time') .': '. $item['runningtime'] .' '. t('minutes') .'
'; + $output .= '

' . l(check_markup($item['title']), $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))) . ' (' . check_plain($date[0]) . ')

'; + $output .= '
' . t('Director') . ': ' . implode(', ', $item['director']) . '
'; + $output .= '
' . t('Rating') . ': ' . $item['audiencerating'] . '
'; + $output .= '
' . t('Running time') . ': ' . $item['runningtime'] . ' ' . t('minutes') . '
'; $output .= '
'; break; } return $output; } +/** + * Theme with inline item dvd. + * @param $item + * @return + * rendered output. + */ function theme_amazon_inline_item_dvd($item) { + $type = $item['type']; $date = split('-', $item['theatricalreleasedate']); - $output = ''; + $output = ''; $output .= l($item['title'] . ' (' . $date[0] . ')', $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))); $output .= ''; return $output; @@ -38,7 +56,7 @@ function theme_amazon_inline_item_dvd($item) { function theme_amazon_inline_item_software($item) { - $output = ''; + $output = ''; $output .= l($item['title'] . ' (' . $item['operatingsystem'] . ')', $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))); $output .= ''; return $output; @@ -46,7 +64,7 @@ function theme_amazon_inline_item_software($item) { function theme_amazon_inline_item_video_games($item) { - $output = ''; + $output = ''; $output .= l($item['title'] . ' (' . $item['hardwareplatform'] . ')', $item['detailpageurl'], array('attributes' => array('rel' => 'nofollow'))); $output .= ''; return $output; diff --git amazon_search/amazon_search.info amazon_search/amazon_search.info index 6eaec9c..1791700 100644 --- amazon_search/amazon_search.info +++ amazon_search/amazon_search.info @@ -3,5 +3,7 @@ description = Provides an API for searching Amazon product information, and inte package = Amazon dependencies[] = amazon dependencies[] = search -core = 6.x +core = 7.x php = 5.2 + +files[] = amazon_search.module diff --git amazon_search/amazon_search.module amazon_search/amazon_search.module index 877c531..4b90698 100644 --- amazon_search/amazon_search.module +++ amazon_search/amazon_search.module @@ -1,38 +1,66 @@ array( + 'title' => t('Access Amazon Search'), + 'description' => t('Perform searches on Amazon.'), + ), + ); +} -function amazon_search_perm() { - return array('access amazon search'); +/** + * Implements hook_search_access(). + */ +function amazon_search_search_access() { + return user_access('access amazon search'); } +function amazon_search_search_info() { + return array( + 'title' => 'Amazon', + 'path' => 'amazon_search', + ); +} /** - * Implementation of hook_search(). Implements remote Amazon searching. + * Implements hook_search(). Implements remote Amazon searching. */ -function amazon_search_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) { - switch ($op) { - case 'name': - if ($skip_access_check || user_access('access amazon search')) { - return t('Amazon.com'); - } - case 'search': - if (user_access('access amazon search')) { - $products = array(); - $items = amazon_search_simple_search($keys); - foreach ($items as $item) { - $products[] = array( - 'title' => check_plain($item['title']), +function amazon_search_search_execute($keys = NULL) { + $products = array(); + $items = amazon_search_simple_search($keys); + foreach ($items as $item) { + $products[] = array( + 'title' => filter_xss($item['title']), 'link' => check_url($item['detailpageurl']), 'type' => check_plain($item['productgroup']), 'user' => isset($item['participants']) ? implode(', ', $item['participants']) : '', - 'snippet' => isset($item['editorialreviews']) ? check_markup($item['editorialreviews'][0]['content']) : '', - ); - } - return $products; - } + 'snippet' => isset($item['editorialreviews']) ? filter_xss($item['editorialreviews'][0]['content']) : '', + ); } + return $products; } +/** + * Perform the search. + * + * @param $keywords + * Keywords to be provided to Amazon. + * @param $parameters + * Optional extra parameters to be passed to the Amazon API. + * @return + * Array of Amazon items. + */ function amazon_search_simple_search($keywords = '', $parameters = array()) { $parameters += array( 'ResponseGroup' => 'ItemAttributes,EditorialReview', @@ -43,9 +71,9 @@ function amazon_search_simple_search($keywords = '', $parameters = array()) { $items = array(); $results = amazon_http_request('ItemSearch', $parameters); - foreach($results->Items->Item as $xml) { + foreach ($results->Items->Item as $xml) { $item = amazon_item_clean_xml($xml); $items[$item['asin']] = $item; } return $items; -} \ No newline at end of file +} diff --git asin/asin.d5-migrate.inc asin/asin.d5-migrate.inc deleted file mode 100644 index 5f0fc51..0000000 --- asin/asin.d5-migrate.inc +++ /dev/null @@ -1,78 +0,0 @@ -nid; - } - - foreach ($nids as $nid) { - if ($node = _asin_migrate_from_d5($nid, $fields)) { - $context['results'][$node->nid] = $node->title; - - $context['sandbox']['progress']++; - $context['sandbox']['current_node'] = $node->nid; - $context['message'] = t('Now processing %node', array('%node' => $node->title)); - } - } - // Inform the batch engine that we are not finished, - // and provide an estimation of the completion level we reached. - if ($context['sandbox']['progress'] != $context['sandbox']['max']) { - $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max']; - } -} - -/** - * Batch 'finished' callback - */ -function _asin_migrate_fields_finished($success, $results, $operations) { - if ($success) { - // Here we do something meaningful with the results. - $message = count($results) .' nodes migrated to new ASIN field structure.'; - $message .= theme('item_list', $results); - } - else { - // An error occurred. - // $operations contains the operations that remained unprocessed. - $error_operation = reset($operations); - $message = 'An error occurred while processing '. $error_operation[0] .' with arguments :'. print_r($error_operation[0], TRUE); - } - drupal_set_message($message); -} - -function _asin_migrate_from_d5($nid, $fields) { - $results = db_query("SELECT asin, ntype FROM {amazonnode} an WHERE an.nid = %d", $nid); - $dirty = FALSE; - $node = node_load($nid); - - while ($asin = db_fetch_object($results)) { - if (array_key_exists($asin->ntype, $fields)) { - $node->{$asin->ntype}[]['asin'] = $asin->asin; - } - } - - node_save($node); - $sql = "DELETE FROM {amazonnode} WHERE nid = %d AND ntype IN (" . db_placeholders($fields, 'varchar') . ")"; - $params = array_keys($fields); - array_unshift($params, $nid); - db_query($sql, $params); - - return $node; -} \ No newline at end of file diff --git asin/asin.info asin/asin.info index 9c016b6..65261a6 100644 --- asin/asin.info +++ asin/asin.info @@ -3,5 +3,9 @@ description = Provides a CCK field type for Amazon products. package = Amazon dependencies[] = amazon dependencies[] = content -core = 6.x +core = 7.x php = 5.2 + +files[] = asin.d5-migrate.inc +files[] = asin.install +files[] = asin.module diff --git asin/asin.install asin/asin.install index dd361ce..02c910e 100644 --- asin/asin.install +++ asin/asin.install @@ -1,8 +1,14 @@ 'varchar', 'length' => 32, 'not null' => FALSE); - $field['widget']['type'] = 'asin_text'; - - content_alter_db($field, $new_field); - content_field_instance_update($field); - - $ret[] = array('success' => TRUE, 'query' => 'Updated database schema and widget settings for ' . $field['field_name']); - } - - content_clear_type_cache(TRUE); - - return $ret; -} - -/** - * Migrate old data from the D5 version. - */ -function asin_update_6002() { - module_load_install('content'); - module_load_include('inc', 'content', 'includes/content.admin'); - module_load_include('inc', 'content', 'includes/content.crud'); - - // Grab the list of fields to update. - $fields = array(); - foreach (content_field_instance_read() as $field) { - if ($field['type'] == 'asin') { - $fields[$field['field_name']] = $field; - } - } - - - if (!empty($fields)) { - $batch = array( - 'title' => t('Migrating ASIN CCK field values'), - 'operations' => array( - array('_asin_migrate_field_from_d5', array($fields)), - ), - 'finished' => '_asin_migrate_fields_finished', - 'init_message' => t('Beginning ASIN migration.'), - 'progress_message' => t('Processed @current out of @total.'), - 'error_message' => t('ASIN CCK field update encountered an error.'), - 'file' => drupal_get_path('module', 'asin') .'/asin.d5-migrate.inc', - ); - batch_set($batch); - } - - return array(); -} \ No newline at end of file diff --git asin/asin.module asin/asin.module index 3230870..61210ca 100644 --- asin/asin.module +++ asin/asin.module @@ -64,16 +64,16 @@ function asin_field_settings($op, $field) { $table_alias = content_views_tablename($field); // Filter: Add a 'many to one' filter. - $copy = $data[$table_alias][$field['field_name'] .'_asin']; + $copy = $data[$table_alias][$field['field_name'] . '_asin']; $copy['title'] = t('@label (!name) - Allowed values', array('@label' => $field['widget']['label'], '!name' => $field['field_name'])); $copy['filter']['handler'] = 'views_handler_filter_many_to_one'; unset($copy['field'], $copy['argument'], $copy['sort']); - $data[$table_alias][$field['field_name'] .'_value_many_to_one'] = $copy; + $data[$table_alias][$field['field_name'] . '_value_many_to_one'] = $copy; // Argument : swap the handler to the 'many to one' operator. - $data[$table_alias][$field['field_name'] .'_value']['argument']['handler'] = 'views_handler_argument_many_to_one'; + $data[$table_alias][$field['field_name'] . '_value']['argument']['handler'] = 'views_handler_argument_many_to_one'; // Add a relationship for related node. - $data[$table_alias][$field['field_name'] .'_asin']['relationship'] = array( + $data[$table_alias][$field['field_name'] . '_asin']['relationship'] = array( 'base' => 'amazon_item', 'field' => $db_info['columns']['asin']['column'], 'handler' => 'views_handler_relationship', @@ -100,7 +100,7 @@ function asin_field($op, &$node, $field, &$items, $teaser, $page) { foreach ($items as $delta => $item) { if (is_array($item)) { if (!empty($item['asin']) && empty($results[$item['asin']])) { - form_set_error($field['field_name'] .']['. $delta .'][asin', t('%name : No Amazon product with the ASIN "%id" could be located.', array('%name' => $field['widget']['label'], '%id' => $item['asin']))); + form_set_error($field['field_name'] . '][' . $delta . '][asin', t('%name : No Amazon product with the ASIN "%id" could be located.', array('%name' => $field['widget']['label'], '%id' => $item['asin']))); } } } @@ -201,7 +201,7 @@ function theme_asin_formatter_default($element) { $asins = array(); if (!empty($asin)) { $asins = amazon_item_lookup("$asin"); - return theme('amazon_item', $asins["$asin"]); + return theme('amazon_item', array('item' => $asins["$asin"])); } } @@ -213,7 +213,7 @@ function theme_asin_formatter_thumbnail($element) { $asin = trim($element['#item']['asin']); if (!empty($asin)) { $asins = amazon_item_lookup("$asin"); - return theme('amazon_item', $asins["$asin"], 'thumbnail'); + return theme('amazon_item', array('item' => $asins["$asin"], 'style' => 'thumbnail')); } } @@ -225,7 +225,7 @@ function theme_asin_formatter_details($element) { $asin = trim($element['#item']['asin']); if (!empty($asin)) { $asins = amazon_item_lookup(array($asin)); - return theme('amazon_item', $asins["$asin"], 'details'); + return theme('amazon_item', array('item' => $asins["$asin"], 'style' => 'details')); } } @@ -236,11 +236,12 @@ function theme_asin_formatter_details($element) { function theme_asin_formatter_inline($element) { if ($asin = trim($element['#item']['asin'])) { $asins = amazon_item_lookup("$asin"); - if (empty($asins[$asin])) { // DEBUG + if (empty($asins[$asin])) { + // DEBUG drupal_set_message("
\$asins[$asin]=" . print_r($asins["$asin"], TRUE) .  "
"); - drupal_set_message("asin='$asin'; asins=".print_r($asins,TRUE)); + drupal_set_message("asin='$asin'; asins=" . print_r($asins, TRUE)); } - return theme('amazon_inline_item', $asins[$asin]); + return theme('amazon_inline_item', array('item' => $asins[$asin])); } } @@ -369,12 +370,12 @@ function asin_text_validate($element, &$form_state) { function theme_asin_text($element) { - drupal_add_css(drupal_get_path('module', 'asin') .'/asin.css', 'module', 'all', FALSE); + drupal_add_css(drupal_get_path('module', 'asin') . '/asin.css', array('preprocess' => FALSE)); $output = $element['#children']; if (!empty($element['#value']) && !empty($element['#value']['asin'])) { $asin = $element['#value']['asin']; if ($data = amazon_item_lookup(array($asin))) { - $output .= '

'. check_plain($data[$asin]['title']) .'

'; + $output .= '

' . check_plain($data[$asin]['title']) . '

'; } } return $output; diff --git includes/amazon.views.inc includes/amazon.views.inc index 474aec8..26ee056 100644 --- includes/amazon.views.inc +++ includes/amazon.views.inc @@ -138,8 +138,8 @@ function amazon_views_data() { _amazon_make_simple_text_field($data, 'amazon_item', 'amazonpriceformattedprice', 'Amazon price (formatted)', "Amazon's current price for the item."); _amazon_make_simple_boolean_field($data, 'amazon_item', 'invalid_asin', 'Invalid ASIN', 'If nonzero, the ASIN is invalid or discontinued by Amazon'); unset($data['amazon_item']['listpriceformattedprice']['argument']); - unset($data['amazon_item']['lowestformattedprice']['argument']); - unset($data['amazon_item']['amazonpriceformattedprice']['argument']); + unset($data['amazon_item']['lowestformattedprice']['argument']); + unset($data['amazon_item']['amazonpriceformattedprice']['argument']); // Define the base group of this table. Fields that don't // have a group defined will go into this field by default. diff --git includes/views_handler_field_amazon_date.inc includes/views_handler_field_amazon_date.inc index ef8fdaa..0bd3e0e 100644 --- includes/views_handler_field_amazon_date.inc +++ includes/views_handler_field_amazon_date.inc @@ -10,7 +10,7 @@ class views_handler_field_amazon_date extends views_handler_field_date { function options_form(&$form, &$form_state) { parent::options_form($form, $form_state); - $time = time(); + $time = REQUEST_TIME; $form['date_format']['#options'] = array( 'default' => format_date($time, 'custom', 'Y-m-d'), 'custom' => t('Custom'), @@ -29,7 +29,7 @@ class views_handler_field_amazon_date extends views_handler_field_date { return theme('views_nodate'); } else { - $time_diff = time() - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence) + $time_diff = REQUEST_TIME - $value; // will be positive for a datetime in the past (ago), and negative for a datetime in the future (hence) switch ($format) { case 'custom': return format_date($value, $format, $custom_format); diff --git includes/views_handler_field_amazon_image.inc includes/views_handler_field_amazon_image.inc index 9f2485b..24872b4 100644 --- includes/views_handler_field_amazon_image.inc +++ includes/views_handler_field_amazon_image.inc @@ -103,22 +103,24 @@ class views_handler_field_amazon_image extends views_handler_field { // Choose presentation style if ($this->options['presentation_format'] == 'markup') { - $image = theme('image', $values->{$this->table_alias . '_url'}, NULL, NULL, $attributes, FALSE); - } else { + $image = theme('image', array('path' => $values->{$this->table_alias . '_url'}, 'alt' => NULL, 'title' => NULL, 'attributes' => $attributes, 'getsize' => FALSE)); + } + else { $image = $values->{$this->table_alias . '_url'}; } - switch($this->options['link_format']) { + switch ($this->options['link_format']) { case 'plain': return $image; break; case 'node': - return l($image, 'node/'. $values->nid, array('html' => TRUE)); + return l($image, 'node/' . $values->nid, array('html' => TRUE)); break; case 'amazon': if (!empty($values->{$this->aliases['detailpageurl']})) { $urlfield = $values->{$this->aliases['detailpageurl']}; return l($image, $urlfield, array('html' => TRUE)); - } else { + } + else { return $image; } break; diff --git includes/views_handler_field_amazon_title.inc includes/views_handler_field_amazon_title.inc index 582244b..12e67a0 100644 --- includes/views_handler_field_amazon_title.inc +++ includes/views_handler_field_amazon_title.inc @@ -38,12 +38,12 @@ class views_handler_field_amazon_title extends views_handler_field { function render($values) { $title = check_plain($values->{$this->field_alias}); - switch($this->options['link_format']) { + switch ($this->options['link_format']) { case 'plain': return $title; break; case 'node': - return l($title, 'node/'. $values->nid, array('html' => TRUE)); + return l($title, 'node/' . $values->nid, array('html' => TRUE)); break; case 'amazon': return l($title, check_url($values->{$this->table_alias . '_detailpageurl'}), array('html' => TRUE)); diff --git includes/views_handler_filter_amazon_node_module.inc includes/views_handler_filter_amazon_node_module.inc index 6f0efd3..a77022a 100644 --- includes/views_handler_filter_amazon_node_module.inc +++ includes/views_handler_filter_amazon_node_module.inc @@ -24,52 +24,3 @@ class views_handler_filter_amazon_node_module extends views_handler_filter_in_op } } -class views_handler_field_amazon_title extends views_handler_field { - function options(&$options) { - parent::options($options); - $options['link_format'] = 'amazon'; - } - - /** - * Override init function to provide generic option to link to node. - */ - function init(&$view, &$data) { - parent::init($view, $data); - if (!empty($data['link_format']) && $data['link_format'] == 'amazon') { - $this->additional_fields[] = 'detailpageurl'; - } - } - - /** - * Provide link to node option - */ - function options_form(&$form, &$form_state) { - $form['link_format'] = array( - '#title' => t('Link behavior'), - '#type' => 'radios', - '#options' => array( - 'plain' => t('No link'), - 'amazon' => t("A link to the product's Amazon page"), - ), - '#default_value' => !empty($this->options['link_format']) ? $this->options['link_format'] : 'plain', - ); - if ($this->view->base_table == 'node') { - $form['link_format']['#options']['node'] = t('A link to the node the product is associated with'); - } - } - - function render($values) { - $title = check_plain($values->{$this->field_alias}); - switch($this->options['link_format']) { - case 'plain': - return $title; - break; - case 'node': - return l($title, 'node/'. $values->nid, array('html' => TRUE)); - break; - case 'amazon': - return l($title, check_url($values->{$this->table_alias . '_detailpageurl'}), array('html' => TRUE, 'attributes' => array('rel' => 'nofollow'))); - break; - } - } -} diff --git includes/views_handler_filter_string_compare.inc includes/views_handler_filter_string_compare.inc index 0fb7818..ba4a551 100644 --- includes/views_handler_filter_string_compare.inc +++ includes/views_handler_filter_string_compare.inc @@ -241,7 +241,7 @@ class views_handler_filter_string_compare extends views_handler_filter { foreach ($matches as $match) { $phrase = false; // Strip off phrase quotes - if ($match[2]{0} == '"') { + if ($match[2][0] == '"') { $match[2] = substr($match[2], 1, -1); $phrase = true; }