We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 27716
    • 126 Posts
    Hi Guys,

    I found the below snippet that parses CSV’s and outputs a table.

    It works fine, but I want to simplify it so that i can enter a string that is the file name in the CSV file, and based on that string it will display a view count.

    see an example csv at Thailand.TV/ttv.csv

    So my resulting snippet call would be

    [[csv2table? &csv=`/ttv.csv` &url=`http://thailand.tv/assets/videos/hQHostel/hq.flv`]]


    And the resulting output would simply be 14

    Any guidance appreciated.

    Stuart

    <?php
    # csv2table 0.1 - Converts CSV to HTML table
    # Created by Chris Pratt 09/08/09.
    # -----------------------------------------------------
    # _Version_History_
    # 0.1 - Inital Release
    # 
    # _Basic_Usage_
    # This snippet will only return the content of the table and not the
    # opening and closing <table> tags. This is by design to allow you to
    # add any attributes, classes or id to the table at will.
    #
    # Ex.
    #
    #   <table>
    #     [[csv2table? &csv=`/path/to/file.csv`]]
    #   </table>
    #
    # _Parameters_
    # &csv           : Path to CSV file (relative to document root)
    # &delimiter     : Character that separates values (defaults to `,`)
    # &enclosure     : Character that encloses strings (defaults to `"`)
    # &hasColHeader  : First row is column headings (boolean 0 or 1, defaults to 1)
    # &hasRowHeader  : First column of each row is a header (boolean 0 or 1, defaults to 0)
    # &alternateRows : Add a class to every 2nd row (boolean 0 or 1, defaults to 1)
    # &altRowClass   : Classname to use for alternating rows (defaults to `alt`)
    #
    # _Notes_
    # MODx snippets can be called with either `[[...]]` or `[!...!]`. The first
    # is a "cached" snippet call: the results of the snippet will be saved and
    # used again later instead of re-running the snippet. The second form is an
    # "uncached" snippet call: the results will not be saved and the snippet will
    # be run each time. Processing CSV files, especially large CSV files, may
    # consume an inordinant amount of resources, so you should always used the
    # "cached" version (`[[...]]`) of the snippet call to save processing time.
    
    
    $params = array(
      'csv' => isset($csv) ? $csv : '',
      'delimiter' => isset($delimiter) ? $delimiter : ',',
      'enclosure' => isset($enclosure) ? $enclosure : '"',
      'hasColHeader' => isset($hasColHeader) ? $hasColHeader : 1,
      'hasRowHeader' => isset($hasRowHeader) ? $hasRowHeader : 0,
      'alternateRows' => isset($alternateRows) ? $alternateRows : 1,
      'altRowClass' => isset($altRowClass) ? $altRowClass : 'alt'
    );
    
    class Csv2table {
      var $params;
      var $fp;
      
      function Csv2table (&$params) {
        //destructor
        register_shutdown_function(array(&$this, ‘__destruct’));
    
        //constructor
        $argcv = func_get_args();
        call_user_func_array(array(&$this, ‘__construct’), $argcv);
      }
      
      function __construct(&$params) {
        $this->params = $params;
      } // __construct
      
      function __destruct() {
        if ($this->fp) fclose($this->fp);
        unset($this->params);
        unset($this->fp);
      } // __destruct
      
      function load_csv_file () {
        if (isset($this->params['csv'])) {
          if (substr($this->params['csv'],0,1) != '/') $this->params['csv'] = '/'.$this->params['csv'];
          if (file_exists("{$_SERVER['DOCUMENT_ROOT']}{$this->params['csv']}")) {
            $this->fp = fopen("{$_SERVER['DOCUMENT_ROOT']}{$this->params['csv']}", 'rb');
          } else {
            return 'Could not find CSV file!';
          }
        } else {
          return 'No CSV file specified!';
        }
        
        if (!$this->fp) {
          return 'Could not open CSV file!';
        }
        
        return false;
      } // load_csv_file
      
      function build_table () {
        $output = '';
        
        if ($this->params['hasColHeader']) {
          $row = fgetcsv($this->fp, 1024, $this->params['delimiter'], $this->params['enclosure']);
          $output .= '    <tr class="heading">'."\n";
          foreach($row as $v) {
            $v = ($v == '') ? ' ' : htmlentities($v);
            $output .= '     <td>'.$v.'</td>'."\n";
          }
          $output .= '    </tr>'."\n";
        }
    
        $row_count = 0;
        while ($row = fgetcsv($this->fp, 1024, $this->params['delimiter'], $this->params['enclosure'])) {
          $row_count++;
    
          $row_class = ($this->params['alternateRows'] && (($row_count % 2) == 0)) ? ' class="'.$this->params['altRowClass'].'"' : '';
    
          $output .= '    <tr'.$row_class.'>'."\n";
          foreach($row as $k => $v) {
            $v = ($v == '') ? ' ' : htmlentities($v);
    
            if (($k == 0) && $this->params['hasRowHeader']) {
              $output .= '      <th>'.$v.'</th>'."\n";
            } else {
              $output .= '      <td class="norm">'.$v.'</td>'."\n";
            }
          }
          $output .= '    </tr>'."\n";
        }
        if ($this->params['hasColHeader']) {
        }
        
        return $output;
      } // build_table
      
      function get_output () {
        if (!$this->fp) $errors = $this->load_csv_file();
        if ($errors) return $errors;
        elseif (!$this->fp) return 'Could not open CSV file!';
        else return $this->build_table();
      } // get_output
      
    }
    
    $csv2table = new Csv2table($params);
    return $csv2table->get_output();
      • 33968
      • 863 Posts
      This should do it for you - duplicate your csv2table snippet and rename to ’csvViewCount’ or something like that.

      Add
        'url' => isset($url) ? $url : '',
      

      to the ’$params’ array at the top of the code.

      Then replace all of
      function build_table () {
        ...
      }
      

      with
        function get_viewcount () {
          $output = '';
          
          while (($row = fgetcsv($this->fp, 1024, $this->params['delimiter'], $this->params['enclosure'])) !== FALSE) {
             if ($row[0] == $this->params['url']) { 
                $output = $row[1];
       	   }
      	}
          return $output;
        } 
      


      And finally go down to function get_output () and replace
          else return $this->build_table();
        } // get_output
      

      with
          else return $this->get_viewcount();
        } // get_output
      



      Then in your template...
      [[csvViewCount? &csv=`/ttv.csv` &url=`http://thailand.tv/assets/videos/hQHostel/hq.flv`]]

      ...will return 14 smiley
        • 27716
        • 126 Posts
        Hi Lucas,

        Thanks so much for your response.

        Didn’t realize anyone had responded to the thread because I forgot to track it smiley

        Will try this tomorrow and let you know how it goes.

        Stuart
          • 27716
          • 126 Posts
          Hi Lucas,

          This worked. Pretty Handy snippet IMO.

          It is falling over when the snippet is called twice on the same page with a different URL.

          So when it has to access the CSV twice it is failing.

          Any idea why this is happening?

          What do you think of the as a solution where I have to call it on 20 times on a page?

          Is it going to be super slow?

          Any guideance appreciated.
          
          $params = array(
            'url' => isset($url) ? $url : '',
            'csv' => isset($csv) ? $csv : '',
            'delimiter' => isset($delimiter) ? $delimiter : ',',
            'enclosure' => isset($enclosure) ? $enclosure : '"',
            'hasColHeader' => isset($hasColHeader) ? $hasColHeader : 1,
            'hasRowHeader' => isset($hasRowHeader) ? $hasRowHeader : 0,
            'alternateRows' => isset($alternateRows) ? $alternateRows : 1,
            'altRowClass' => isset($altRowClass) ? $altRowClass : 'alt'
          );
          
          class Csv2table {
            var $params;
            var $fp;
            
            function Csv2table (&$params) {
              //destructor
              register_shutdown_function(array(&$this, ‘__destruct’));
          
              //constructor
              $argcv = func_get_args();
              call_user_func_array(array(&$this, ‘__construct’), $argcv);
            }
            
            function __construct(&$params) {
              $this->params = $params;
            } // __construct
            
            function __destruct() {
              if ($this->fp) fclose($this->fp);
              unset($this->params);
              unset($this->fp);
            } // __destruct
            
            function load_csv_file () {
              if (isset($this->params['csv'])) {
                if (substr($this->params['csv'],0,1) != '/') $this->params['csv'] = '/'.$this->params['csv'];
                if (file_exists("{$_SERVER['DOCUMENT_ROOT']}{$this->params['csv']}")) {
                  $this->fp = fopen("{$_SERVER['DOCUMENT_ROOT']}{$this->params['csv']}", 'rb');
                } else {
                  return 'Could not find CSV file!';
                }
              } else {
                return 'No CSV file specified!';
              }
              
              if (!$this->fp) {
                return 'Could not open CSV file!';
              }
              
              return false;
            } // load_csv_file
            
            function get_viewcount () {
              $output = '';
              
              while (($row = fgetcsv($this->fp, 1024, $this->params['delimiter'], $this->params['enclosure'])) !== FALSE) {
                 if ($row[0] == $this->params['url']) { 
                    $output = $row[1];
           	   }
          	}
              return $output;
            } 
            function get_output () {
              if (!$this->fp) $errors = $this->load_csv_file();
              if ($errors) return $errors;
              elseif (!$this->fp) return 'Could not open CSV file!';
                else return $this->get_viewcount();
            } // get_output
            
          }
          
          $csv2table = new Csv2table($params);
          return $csv2table->get_output();
            • 27716
            • 126 Posts
            Ok, now decided to abandon this approach grin

            Back to using the GAPI class

            http://modxcms.com/forums/index.php?topic=63795.new;topicseen#new

            Have actually got it outputting in Revo.

            Will tweak it a bit and update that thread with some Qs...and so people have a reference for GAPI / Revo

            Stuart
              • 33968
              • 863 Posts
              Are you listing a bunch of videos on a page, with the number of views for each?
              I see where this method might not be optimal smiley

              I’ve dabbled with GAPI but found it to be quite slow for use on a front end page. Perhaps there could be an easier way to track views using a snippet and a custom db table to store views in? What about something like: PageHitCounter

              Should be easy to convert over to Revo.
                • 27716
                • 126 Posts
                Hi Lucas,

                It looks like the Page hit counter will count pages.

                For video views Im currently tracking events, when the user clicks the play button.

                I probably shouldnt use pageview, as it will inflate the count alot.

                Did a few pings with the GAPI and it did slow it down.

                Think if I can get the call to a stage of pulling a singly count out for each video it won’t be too slow. But not sure on a page with 20 videos.

                Will work on it and see how it goes.
                  • 27716
                  • 126 Posts
                  Do you think it would be possible to code this so that each Template variable referenced the GA event label,

                  and stored the value from the API as a static value.

                  And then i could manually execute a script that pulls all of the values from GA and stores them.

                  Would be a good way to prevent any reduction in page speed.
                    • 33968
                    • 863 Posts
                    Do you think it would be possible to code this so that each Template variable referenced the GA event label... and then manually execute a script that pulls all of the values from GA and stores them.
                    You could do that, and even have your script run and update every evening so you wouldn’t have to do it manually. But there’s probably a better way...

                    How are you tracking the ’play’ event?

                    It might be that you could link that event to a simple ajax call which would execute PageHitCounter when the video is played. You would then have ’real time’ updates on the hit counter rather than waiting for a daily update from Google.
                      • 27716
                      • 126 Posts
                      Hi Lucas,

                      I’m tracking the play event with GA Event tracking.

                      I’m not so concerned about real time. One update every day or 2 is NP.

                      With either of these solutions there will be a snippet that outputs a video view count.

                      Either Via CSV or the GA API.

                      The prob with Both is the site speed issue.

                      Using the CSV solution as an example, how could I execute the snippet in one TV, and then have another TV that just holds output as static value.

                      Any guidance appreciated.

                      With over 100 videos now manual updates is getting crazy. Will soon spend 24 hours a day just updating view counts smiley

                      Stuart