Fix for Node To Word Stats module, dev snapshot

  1. <?php
  2. // $Id$
  3.  
  4. /*
  5.  * Created by Greg Harvey on 26 Jul 2010
  6.  *
  7.  * http://www.drupaler.co.uk
  8.  */
  9.  
  10. /**
  11.  * Helper function for returning node ID for given document
  12.  * download path.
  13.  *
  14.  * @param $path
  15.  *  (string) The path from the accesslog table.
  16.  *
  17.  * @param $type
  18.  *  (string) The type of download, either 'word' or 'txt'.
  19.  *
  20.  * @return
  21.  *  Valid Drupal node ID or NULL if no node ID found in the path.
  22.  */
  23. function node_to_word_stats_nid_from_path($path, $type) {
  24.   $nid = NULL;
  25.   $pattern = '/' . $type . '\/([0-9]*)/';
  26.   // Find the nid in the specified path.
  27.   preg_match($pattern, $path, $matches);
  28.   // Make sure we have an ID.
  29.   if (is_numeric($matches[1])) {
  30.     $nid = $matches[1];
  31.   }
  32.   return $nid;
  33. }
  34.  
  35. /**
  36.  * Implementation of hook_perm().
  37.  */
  38. function node_to_word_stats_perm() {
  39.   return array('access node to word statistics', 'administer node to word statistics settings');
  40. }
  41.  
  42. /**
  43.  * Implementation of hook_menu().
  44.  */
  45. function node_to_word_stats_menu() {
  46.   $items = array();
  47.  
  48.   $items['admin/reports/ntw-downloads'] = array(
  49.     'title callback' => 'node_to_word_stats_article_list_title',
  50.     'title arguments' => array('all'),
  51.     'description' => t('Pages for viewing access log data for Node To Word file downloads using data provided by the core Statistics module in a more useful way.'),
  52.     'page callback' => 'node_to_word_stats_article_list',
  53.     'page arguments' => array('all'),
  54.     'access arguments' => array('access node to word statistics'),
  55.   );
  56.  
  57.   $items['admin/reports/ntw-downloads/all'] = array(
  58.     'title callback' => 'node_to_word_stats_article_list_title',
  59.     'title arguments' => array('all'),
  60.     'description' => t('Pages for viewing access log data for Node To Word file downloads using data provided by the core Statistics module in a more useful way.'),
  61.     'page callback' => 'node_to_word_stats_article_list',
  62.     'page arguments' => array('all'),
  63.     'access arguments' => array('access node to word statistics'),
  64.     'type' => MENU_DEFAULT_LOCAL_TASK,
  65.   );
  66.  
  67.   $items['admin/reports/ntw-downloads/field'] = array(
  68.     'title callback' => 'node_to_word_stats_article_list_title',
  69.     'title arguments' => array(3, 4),
  70.     'description' => t('Pages for viewing access log data for Node To Word file downloads using data provided by the core Statistics module in a more useful way.'),
  71.     'page callback' => 'node_to_word_stats_article_list',
  72.     'page arguments' => array(3, 4),
  73.     'access arguments' => array('access node to word statistics'),
  74.     'type' => MENU_CALLBACK,
  75.   );
  76.   // Load articles by user profile field value.
  77.   $items['admin/reports/ntw-downloads/field'] = array(
  78.     'title callback' => 'node_to_word_stats_article_list_title',
  79.     'title arguments' => array(3, 4),
  80.     'description' => t('Pages for viewing access log data for Node To Word file downloads using data provided by the core Statistics module in a more useful way.'),
  81.     'page callback' => 'node_to_word_stats_article_list',
  82.     'page arguments' => array(3, 4),
  83.     'access arguments' => array('access node to word statistics'),
  84.     'type' => MENU_CALLBACK,
  85.   );
  86.   // Load articles by taxonomy term.
  87.   $items['admin/reports/ntw-downloads/category'] = array(
  88.     'title callback' => 'node_to_word_stats_article_list_title',
  89.     'title arguments' => array(3, 4),
  90.     'description' => t('Pages for viewing access log data for Node To Word file downloads using data provided by the core Statistics module in a more useful way.'),
  91.     'page callback' => 'node_to_word_stats_article_list',
  92.     'page arguments' => array(3, 4),
  93.     'access arguments' => array('access node to word statistics'),
  94.     'type' => MENU_CALLBACK,
  95.   );
  96.  
  97.   $field = variable_get('node_to_word_stats_grouping_profile_fid', 3);
  98.   $field_name = db_result(db_query("SELECT title FROM {profile_fields} WHERE fid = %d", $field));
  99.   $items['admin/reports/ntw-downloads/by-profile'] = array(
  100.     'title' => t('Downloads by !field', array('!field' => $field_name)),
  101.     'description' => t('Page for showing content grouped by !field', array('!field' => $field_name)),
  102.     'page callback' => 'node_to_word_stats_by_profile_field',
  103.     'access arguments' => array('access node to word statistics'),
  104.     'type' => MENU_LOCAL_TASK,
  105.   );
  106.  
  107.   $items['admin/reports/ntw-downloads/%node'] = array(
  108.     'title callback' => 'node_to_word_stats_user_list_title',
  109.     'title arguments' => array(3),
  110.     'description' => t('Page for viewing user lists of users who downloaded Word and text versions of a specific node.'),
  111.     'page callback' => 'node_to_word_stats_user_list',
  112.     'page arguments' => array(3, 4),
  113.     'access arguments' => array('access node to word statistics'),
  114.     'type' => MENU_CALLBACK,
  115.   );
  116.  
  117.   return $items;
  118. }
  119.  
  120. /**
  121.  * Callback for setting the article list page title depending on context.
  122.  * See the page callback function below for parameter information.
  123.  */
  124. function node_to_word_stats_article_list_title($filter = 'all', $data = NULL) {
  125.   if ($filter == 'all') {
  126.     return t('All downloads');
  127.   }
  128.   if ($filter == 'field' && $data) {
  129.     drupal_set_title(t('Downloads by !value', array('!value' => $data)));
  130.   }
  131.   if ($filter == 'category' && $data) {
  132.     $term = taxonomy_get_term($data);
  133.     drupal_set_title(t('Downloads in %value', array('%value' => $term->name)));
  134.   }
  135. }
  136.  
  137. /**
  138.  * Callback for setting the user list page title depending on context.
  139.  */
  140. function node_to_word_stats_user_list_title($node) {
  141.   drupal_set_title(t('Users who downloaded %title', array('%title' => $node->title)));
  142. }
  143.  
  144. /**
  145.  * Function for handling user list pages.
  146.  *
  147.  * @param $node
  148.  *  (object) Fully formed Drupal node object.
  149.  *
  150.  * @return
  151.  *  (string) HTML page of results.
  152.  */
  153. function node_to_word_stats_user_list($node, $data = NULL) {
  154.   // Set the table headers.
  155.   $header = array(
  156.     array(
  157.       'data' => 'Username',
  158.       'field' => 'u.name',
  159.     ),
  160.     array(
  161.       'data' => 'Last access',
  162.       'field' => 'a.timestamp',
  163.       'sort' => 'desc',
  164.     ),
  165.     array(
  166.       'data' => 'First name',
  167.     ),
  168.     array(
  169.       'data' => 'Last name',
  170.     ),
  171.     array(
  172.       'data' => 'Organisation',
  173.     ),
  174.     array(
  175.       'data' => 'Telephone',
  176.     ),
  177.   );
  178.   // TODO: make this an admin setting.
  179.   $limit = variable_get('node_to_word_stats_results_per_page', 50);
  180.   // Check to see if we need to restrict results by user profile field.
  181.   if ($data) {
  182.     //print $data;
  183.     // Query the database for list of downloading users, filtered by profile field.
  184.     $query = "SELECT DISTINCT(a.uid) as uid, u.name, a.timestamp
  185.              FROM {accesslog} a
  186.              INNER JOIN {users} u
  187.              ON a.uid = u.uid
  188.              INNER JOIN {profile_values} p
  189.              ON p.uid = a.uid
  190.              WHERE
  191.              (path = CONCAT('txt/',%d) OR path = CONCAT('word/',%d))
  192.              AND p.value = '%s'
  193.              GROUP BY uid"
  194.               . tablesort_sql($header);
  195.     $count_query = "SELECT COUNT(DISTINCT a.uid)
  196.              FROM {accesslog} a
  197.              INNER JOIN {users} u
  198.              ON a.uid = u.uid
  199.              INNER JOIN {profile_values} p
  200.              ON p.uid = a.uid
  201.              WHERE
  202.              (path = CONCAT('txt/',%d) OR path = CONCAT('word/',%d))
  203.              AND p.value = '%s'";
  204.     $result = pager_query($query, $limit, 0, $count_query, $node->nid, $node->nid, $data);
  205.   }
  206.   else {
  207.     // Query the database for list of downloading users.
  208.     $query = "SELECT DISTINCT(a.uid) as uid, u.name, a.timestamp
  209.              FROM {accesslog} a
  210.              INNER JOIN {users} u
  211.              ON a.uid = u.uid
  212.              WHERE
  213.              (path = CONCAT('txt/',%d) OR path = CONCAT('word/',%d))
  214.              GROUP BY uid"
  215.               . tablesort_sql($header);
  216.     $count_query = "SELECT COUNT(DISTINCT a.uid)
  217.              FROM {accesslog} a
  218.              INNER JOIN {users} u
  219.              ON a.uid = u.uid
  220.              WHERE
  221.              (path = CONCAT('txt/',%d) OR path = CONCAT('word/',%d))";
  222.     $result = pager_query($query, $limit, 0, $count_query, $node->nid, $node->nid);
  223.   }
  224.  
  225.   while ($row = db_fetch_array($result)) {
  226.     // Fetch the profile data.
  227.     $profile_query = "SELECT p.value, f.name
  228.              FROM {profile_values} p
  229.              INNER JOIN
  230.              {profile_fields} as f
  231.              ON p.fid = f.fid
  232.              WHERE p.uid = %d";
  233.     $profile_result = db_query($profile_query, $row['uid']);
  234.     while ($profile_field = db_fetch_array($profile_result)) {
  235.       $row[$profile_field['name']] = $profile_field['value'];
  236.     }
  237.     // Set link to company website, if available.
  238.     if ($row['profile_website']) {
  239.       $row['profile_org_name'] = l($row['profile_org_name'], $row['profile_website']);
  240.     }
  241.     // Format the date.
  242.     $row['timestamp'] = format_date($row['timestamp'], 'small');
  243.     // Format the user profile link.
  244.     $row['name'] = l($row['name'], 'user/' . $row['uid']);
  245.     // Unset the data we don't want.
  246.     unset($row['uid']);
  247.     unset($row['profile_org_phone']);
  248.     unset($row['profile_mobile']);
  249.     unset($row['profile_website']);
  250.     $rows[] = $row;
  251.   }
  252.   // Back link.
  253.   $back = '<div><a href="javascript:history.go(-1);" />Back</a></div>';
  254.   // Return a themed table.
  255.   return theme('table', $header, $rows) . $back . theme('pager');
  256. }
  257.  
  258. /**
  259.  * Function for handling article list pages.
  260.  *
  261.  * @param $filter
  262.  *  (string) Either all, field or category.
  263.  *    all = full article list sorted by downloads descending.
  264.  *    field = article list filtered by specified user profile field value.
  265.  *      (Profile module required, field to interrogate an admin setting.)
  266.  *    category = article list filtered by category.
  267.  *
  268.  * @param $data
  269.  *  (mixed) Either the value to pass to a profile field ($filter = 'field')
  270.  *  or a valid Drupal term ID ($filter = 'category').
  271.  *
  272.  * @return
  273.  *  (string) HTML page of results.
  274.  */
  275. function node_to_word_stats_article_list($filter = 'all', $data = NULL) {
  276.   // Set the table headers.
  277.   $header = array(
  278.     array(
  279.       'data' => 'Article',
  280.     ),
  281.     array(
  282.       'data' => 'Total downloads',
  283.       'field' => 'counter',
  284.       'sort' => 'desc',
  285.     ),
  286.   );
  287.  
  288.   // TODO: make this an admin setting.
  289.   $limit = variable_get('node_to_word_stats_results_per_page', 50);
  290.  
  291.   if ($filter == 'all') {
  292.     // Query the database to get all downloaded articles.
  293.     $query = "SELECT a.path, COUNT(a.aid) as counter, a.title
  294.              FROM {accesslog} a
  295.              WHERE (path LIKE 'txt/%'
  296.                OR path LIKE 'word/%')
  297.              GROUP BY a.title"
  298.               . tablesort_sql($header);
  299.     $count_query = "SELECT COUNT(DISTINCT a.title)
  300.              FROM {accesslog} a
  301.              WHERE (path LIKE 'txt/%'
  302.                OR path LIKE 'word/%')";
  303.     $result = pager_query($query, $limit);
  304.   }
  305.   elseif ($filter == 'field') {
  306.     // Query the database to get all articles downloaded by users with a
  307.     // specified user profile value.
  308.     $query = "SELECT a.path, COUNT(a.aid) as counter, a.title
  309.              FROM {accesslog} a
  310.              INNER JOIN {profile_values} p
  311.              ON p.uid = a.uid
  312.              AND p.fid = %d
  313.              AND p.value = '%s'
  314.              WHERE path LIKE 'txt/%'
  315.              OR path LIKE 'word/%'
  316.              GROUP BY a.title"
  317.               . tablesort_sql($header);
  318.     $count_query = "SELECT COUNT(DISTINCT a.title)
  319.              FROM {accesslog} a
  320.              INNER JOIN {profile_values} p
  321.              ON p.uid = a.uid
  322.              AND p.fid = %d
  323.              WHERE path LIKE 'txt/%'
  324.              OR path LIKE 'word/%'";
  325.     $result = pager_query($query, $limit, 0, $count_query, variable_get('node_to_word_stats_grouping_profile_fid', 3), $data);
  326.   }
  327.   elseif ($filter == 'category') {
  328.     // Query the database to get all articles downloaded in a category.
  329.     $query = "SELECT a.path, a.title,
  330.              (SELECT COUNT(aid) FROM accesslog WHERE path = CONCAT('txt/',t.nid) OR path = CONCAT('word/',t.nid)) as counter
  331.              FROM {term_node} t
  332.              INNER JOIN {accesslog} a
  333.              ON
  334.              (CONCAT('txt/',t.nid) = a.path
  335.              OR CONCAT('word/',t.nid) = a.path)
  336.              WHERE t.tid = %d
  337.              GROUP BY a.title"
  338.               . tablesort_sql($header);
  339.     $count_query = "SELECT COUNT(DISTINCT a.title)
  340.              FROM {term_node} t
  341.              INNER JOIN {accesslog} a
  342.              ON
  343.              (CONCAT('txt/',t.nid) = a.path
  344.              OR CONCAT('word/',t.nid) = a.path)
  345.              WHERE t.tid = %d";
  346.     $result = pager_query($query, $limit, 0, $count_query, $data);
  347.   }
  348.  
  349.  
  350.   while ($row = db_fetch_array($result)) {
  351.     // Find the nid.
  352.     $nid = node_to_word_stats_nid_from_path($row['path'], 'txt');
  353.     if (!$nid) {
  354.       $nid = node_to_word_stats_nid_from_path($row['path'], 'word');
  355.     }
  356.     // Change the path to be to the actual node.
  357.     $row['path'] = l($row['title'], 'node/' . $nid);
  358.     // Add the details link.
  359.     if ($data && $filter == 'field') {
  360.       // Make sure we pass on the company name, if we have it.
  361.       $row['details'] = l(t('click for details'), 'admin/reports/ntw-downloads/' . $nid . '/' . $data);
  362.     }
  363.     else {
  364.       $row['details'] = l(t('click for details'), 'admin/reports/ntw-downloads/' . $nid);
  365.     }
  366.     unset($row['title']);
  367.     // Key the $rows array by nid.
  368.     $rows[$nid] = $row;
  369.   }
  370.   // Return a themed table.
  371.   $output = drupal_get_form('node_to_word_stats_filters_form');
  372.   $output .= theme('table', $header, $rows) . theme('pager');
  373.   return $output;
  374. }
  375.  
  376. /**
  377.  * Function for collating and returning themed data to show
  378.  * on the Reports page for Word/txt downloads by a profile
  379.  * field using the core Profile module.
  380.  *
  381.  * TODO: Separate theming out to a template/function.
  382.  */
  383. function node_to_word_stats_by_profile_field() {
  384.   // Set the table headers.
  385.   $header = array(
  386.     array(
  387.       'data' => 'Title',
  388.     ),
  389.     array(
  390.       'data' => 'Total downloads',
  391.       'field' => 'p.value',
  392.       'sort' => 'asc',
  393.     ),
  394.   );
  395.   // Query the database to get all organisations by download count.
  396.   $query = "SELECT p.value as field, COUNT(a.aid) as counter
  397.            FROM {accesslog} as a
  398.            INNER JOIN {profile_values} as p
  399.            ON p.uid = a.uid
  400.            AND p.fid = %d
  401.            WHERE path LIKE 'txt/%'
  402.            OR path LIKE 'word/%'
  403.            GROUP BY field"
  404.             . tablesort_sql($header);
  405.   $count_query = "SELECT COUNT(DISTINCT p.value)
  406.            FROM {accesslog} as a
  407.            INNER JOIN {profile_values} as p
  408.            ON p.uid = a.uid
  409.            AND p.fid = %d
  410.            WHERE path LIKE 'txt/%'
  411.            OR path LIKE 'word/%'";
  412.   // TODO: make this an admin setting.
  413.   $limit = variable_get('node_to_word_stats_results_per_page', 50);
  414.   $result = pager_query($query, $limit, 0, $count_query, variable_get('node_to_word_stats_grouping_profile_fid', 3));
  415.   while ($row = db_fetch_array($result)) {
  416.     $row['field'] = l($row['field'], 'admin/reports/ntw-downloads/field/' . $row['field']);
  417.     $rows[] = $row;
  418.   }
  419.   // Return a themed table and pager.
  420.   return theme('table', $header, $rows) . theme('pager');
  421. }
  422.  
  423. /**
  424.  * Function describing the filters form on the article page.
  425.  */
  426. function node_to_word_stats_filters_form() {
  427.   $categories = array();
  428.   $categories[0] = t('All');
  429.  
  430.   $query = "SELECT * FROM {term_data}";
  431.   $result = db_query($query);
  432.   while ($row = db_fetch_array($result)) {
  433.     $categories[$row['tid']] = $row['name'];
  434.   }
  435.  
  436.   $form = array();
  437.  
  438.   $form['categories'] = array(
  439.     '#type' => 'select',
  440.     '#title' => t('Filter by category'),
  441.     '#default_value' => 0,
  442.     '#options' => $categories,
  443.   );
  444.  
  445.   return $form;
  446. }

Submit Fix

Any tags you'd like to associate with your code, delimitered by commas (example: Views, CCK, Module, etc).
Select the syntax highlighting mode to use.