Source for file export.php

Documentation is available at export.php

  1. <?php
  2. /**
  3. * Export various views of the booking data in numerous formats
  4. *
  5. * @author    Stuart Prescott
  6. * @copyright  Copyright Stuart Prescott
  7. * @license    http://opensource.org/licenses/gpl-license.php GNU Public License
  8. * @version    $Id$
  9. * @package    Bumblebee
  10. * @subpackage Actions
  11. *
  12. *  path (bumblebee root)/inc/actions/export.php
  13. */
  14.  
  15. /** Load ancillary functions */
  16. require_once 'inc/typeinfo.php';
  17.  
  18. require_once 'inc/bb/configreader.php';
  19.  
  20. /** CheckBox object */
  21. require_once 'inc/formslib/checkbox.php';
  22. /** CheckBoxTableList object */
  23. require_once 'inc/formslib/checkboxtablelist.php';
  24. /** Data reflector object */
  25. require_once 'inc/formslib/datareflector.php';
  26. /** parent object */
  27. require_once 'inc/actions/bufferedaction.php';
  28. /** Export formatting codes */
  29. require_once 'inc/exportcodes.php';
  30. /** Export configuration and formatting */
  31. require_once 'inc/export/exporttypes.php';
  32. /** Export method object */
  33. require_once 'inc/export/arrayexport.php';
  34. /** Export method object */
  35. require_once 'inc/export/htmlexport.php';
  36. /** database interrogation object */
  37. require_once 'inc/formslib/dblist.php';
  38. /** list of choices */
  39. require_once 'inc/formslib/anchortablelist.php';
  40. /** list of choices */
  41. require_once 'inc/bb/daterange.php';
  42. /** list of choices */
  43. require_once 'inc/formslib/radiolist.php';
  44.  
  45. /**
  46. * Export various views of the booking data in numerous formats
  47. *
  48. * A number of different data views can be created (see exporttypes.php)
  49. * and the data can be exported in various formats (see htmlexport.php and arrayexport.php)
  50. *
  51. * This class is inherited by other exporters
  52. * @package    Bumblebee
  53. * @subpackage Actions
  54. */
  55. class ActionExport extends BufferedAction {
  56.   /**
  57.   * forces SQL errors to be fatal
  58.   * @var    boolean 
  59.   */
  60.   var $fatal_sql = 1;
  61.   /**
  62.   * name of the export format to be used
  63.   * @var    string 
  64.   */
  65.   var $format;
  66.   /**
  67.   * object containing export SQL and formatting instructions
  68.   * @var    ExportTypeList 
  69.   */
  70.   var $typelist;
  71.   /**
  72.   * the specific ExportType to be used in this data export
  73.   * @var    ExportType 
  74.   */
  75.   var $_export;  // ExportType format description
  76.     /**
  77.   * The data range to be used for data export
  78.   * @var    DateRange 
  79.   */
  80.   var $_daterange;
  81.   /**
  82.   * The original action word (verb!) that instantiated this class (not its descendants)
  83.   * Allows HTML links back to this class to be easily made.
  84.   * @var    string 
  85.   */
  86.   var $_verb = 'export';
  87.  
  88.   /**
  89.   * Initialising the class
  90.   *
  91.   * @param  BumblebeeAuth $auth  Authorisation object
  92.   * @param  array $pdata   extra state data from the call path
  93.   * @return void nothing
  94.   */
  95.   function ActionExport($auth, $pdata) {
  96.     parent::BufferedAction($auth, $pdata);
  97.   }
  98.  
  99.   function go() {
  100.     $reflector = new DataReflector();
  101.     echo $reflector->display($this->PD);
  102.  
  103.     $this->typelist = new ExportTypeList();
  104. //     preDump($this->typelist);
  105.     if (! isset($this->PD['what'])) {
  106.       $this->unbuffer();
  107.       $this->selectExport();
  108.     } else {
  109.       $allDataOK = true;
  110.       $this->_daterange = new DateRange('daterange', T_('Select date range'),
  111.                       T_('Enter the dates over which you want to export data'));
  112.       $this->_daterange->update($this->PD);
  113.       $this->_daterange->checkValid();
  114.       $this->_daterange->reflectData = 0;
  115.       $this->_daterange->includeSubmitButton = 0;
  116.       if ($this->_daterange->newObject || !$this->_daterange->isValid) {
  117.         #echo "don't have date range <br />";
  118.         $allDataOK = false;
  119.         $this->unbuffer();
  120.         $this->_daterange->setDefaults(DR_PREVIOUS, DR_QUARTER);
  121.         echo $this->_daterange->display($this->PD);
  122.       }
  123.       if (! isset($this->format)) {
  124.         #echo "don't have format<br />";
  125.         $allDataOK = false;
  126.         $this->unbuffer();
  127.         $this->formatSelect();
  128.       }
  129.       if (! isset($this->PD['limitationselected'])) {
  130.         #echo "don't have instruments <br />";
  131.         $allDataOK = false;
  132.         $this->unbuffer();
  133.         $this->outputSelect();
  134.       }
  135.       if ($allDataOK) {
  136.         echo $this->reportAction($this->returnExport(),
  137.               array(STATUS_ERR =>  T_('Error exporting data:').' '.$this->errorMessage
  138.                    )
  139.              );
  140.       } else {
  141.         $this->_goButton();
  142.       }
  143.     }
  144.   }
  145.  
  146.   function mungeInputData() {
  147.     parent::mungeInputData();
  148.     if (isset($this->PD['outputformat'])) {
  149.       $this->format = $this->PD['outputformat'];
  150.     }
  151.   }
  152.  
  153.   /**
  154.   * Generate HTML list for user to select which data export should be used
  155.   *
  156.   * @return void nothing
  157.   */
  158.   function selectExport() {
  159.     $reportlist = array();
  160.     foreach ($this->typelist->types as $type) {
  161.       $reportlist[$type->name] = $type->description;
  162.     }
  163.     $select = new AnchorTableList('datasource', T_('Select which data to export'), 1);
  164.     $select->setValuesArray($reportlist, 'id', 'iv');
  165.     $select->hrefbase = makeURL($this->_verb, array('what'=>'__id__'));
  166.     $select->setFormat('id', '%s', array('iv'));
  167.     echo $select->display();
  168.   }
  169.  
  170.   /**
  171.   * Generate HTML list for user to select which data format should be used
  172.   *
  173.   * @return void nothing
  174.   */
  175.   function formatSelect() {
  176.     $conf = ConfigReader::getInstance();
  177.     $formatlist = array(EXPORT_FORMAT_VIEW     => T_('View in web browser'),
  178.                         EXPORT_FORMAT_VIEWOPEN => T_('View in web browser (new window)'),
  179.                         EXPORT_FORMAT_CSV      => T_('Save as comma separated variable (csv)'),
  180.                         EXPORT_FORMAT_TAB      => T_('Save as tab separated variable (txt)'));
  181.     if ($conf->value('export', 'enablePDF')) {
  182.       $formatlist[EXPORT_FORMAT_PDF] = T_('Save as pdf report');
  183.     }
  184.     $select = new RadioList('outputformat', T_('Select which data to export'), 1);
  185.     $select->setValuesArray($formatlist, 'id', 'iv');
  186.     $select->setFormat('id', '%s', array('iv'));
  187.     if (is_numeric($conf->value('export', 'defaultFormat'))) {
  188.       $select->setDefault($conf->value('export', 'defaultFormat'));
  189.     } else {
  190.       $select->setDefault(exportStringToCode($conf->value('export', 'defaultFormat')));
  191.     }
  192.     echo '<div style="margin: 2em 0 2em 0;">'.$select->display().'</div>';
  193.   }
  194.  
  195.   /**
  196.   * Generate HTML form widget for user to control output.
  197.   *
  198.   * User can select which sub-view of the data to use
  199.   * and which specific parts of the data should be included (i.e. restrict by group)
  200.   *
  201.   * @return void nothing
  202.   */
  203.   function outputSelect() {
  204.     $export = $this->typelist->types[$this->PD['what']];
  205.     for ($lim = 0; $lim < count($export->limitation); $lim++) {
  206.       $select = new CheckBoxTableList('limitation-'.$lim, T_('Select which detail to view'));
  207.       $hidden = new TextField($export->limitation[$lim]);
  208.       $select->addFollowHidden($hidden);
  209.       $chosen = new CheckBox('selected', T_('Selected'));
  210.       $select->addCheckBox($chosen);
  211.       //$select->numSpareCols = 1;
  212.       if ($export->limitation[$lim] == 'users') {
  213.         $select->connectDB($export->limitation[$lim], array('id', 'name', 'username'));
  214.         $select->setFormat('id', '%s', array('name'), " (%s)", array('username'));
  215.       } else {
  216.         $select->connectDB($export->limitation[$lim], array('id', 'name', 'longname'));
  217.         $select->setFormat('id', '%s', array('name'), " %50.50s", array('longname'));
  218.       }
  219.       $select->addSelectAllFooter(true);
  220.       echo $select->display().'<br/>';
  221.     }
  222.     if (is_array($export->pivot) && count($export->pivot) > 1) {
  223.       $views = array();
  224.       foreach ($export->pivot as $k => $v) {
  225.         $views[$k] = $v['description'];
  226.       }
  227.       $viewselect = new RadioList('pivot', T_('Select which data view to export'), 1);
  228.       $viewselect->setValuesArray($views, 'id', 'iv');
  229.       $viewselect->setFormat('id', '%s', array('iv'));
  230.       reset($views);
  231.       $viewselect->setDefault(key($views));
  232.       echo '<div style="margin: 0em 0 2em 0;">'.$viewselect->display().'</div>';
  233.     }
  234.     echo '<input type="hidden" name="limitationselected" value="1" />';
  235.   }
  236.  
  237.   /**
  238.   * Common submit button for this class
  239.   *
  240.   * @return void nothing
  241.   */
  242.   function _goButton() {
  243.     echo '<input type="submit" name="submit" value="'.T_('Select').'" />';
  244.   }
  245.  
  246.   /**
  247.   * Generate the data export and then send it to the user in the appropriate format
  248.   *
  249.   * @return void nothing
  250.   */
  251.   function returnExport() {
  252.     $list = $this->_getDataList($this->PD['what']);
  253.     $list->fill();
  254.     if (count($list->data) == 0) {
  255.       return $this->unbufferForError('<p>'.T_('No data found for those criteria').'</p>');
  256.     }
  257.     // start rendering the data
  258.     $list->outputFormat = $this->format;
  259.     $list->formatList();
  260.     if ($this->format & EXPORT_FORMAT_USEARRAY) {
  261.       $exportArray = new ArrayExport($list, $list->breakfield);
  262.       $exportArray->header = $this->_reportHeader();
  263.       $exportArray->author = $this->auth->name;
  264.       $exportArray->makeExportArray();
  265.       //preDump($exportArray->export);
  266.     }
  267.     if ($this->format & EXPORT_FORMAT_USEHTML) {
  268.       $htmlExport = new HTMLExport($exportArray);
  269.       $htmlExport->makeHTMLBuffer();
  270.     }
  271.  
  272.     //finally, direct the data towards its output
  273.     if ($this->format == EXPORT_FORMAT_PDF){
  274.       // construct the PDF from $htmlbuffer
  275.       $pdfExport = $this->_preparePDFExport($exportArray);
  276.       $pdfExport->makePDFBuffer();
  277.  
  278.       if ($pdfExport->writeToFile) {
  279.         $this->unbuffer();
  280.       } else {
  281.         $this->_getFilename();
  282.         $this->bufferedStream =& $pdfExport->export;
  283.         // the data itself will be dumped later by the action driver (index.php)
  284.       }
  285.     } elseif ($this->format & EXPORT_FORMAT_DELIMITED) {
  286.       $this->_getFilename();
  287.       $this->bufferedStream = '"'.$this->_reportHeader().'"'."\n"
  288.                                .$list->outputHeader()."\n"
  289.                                .join($list->formatdata, "\n");
  290.       // the data itself will be dumped later by the action driver (index.php)
  291.     } elseif ($this->format == EXPORT_FORMAT_VIEWOPEN) {
  292.       $this->unbuffer();
  293.       echo $htmlExport->wrapHTMLBuffer();
  294.     } else {
  295.       $this->unbuffer();
  296.       echo $htmlExport->export;
  297.     }
  298.   }
  299.  
  300.   /**
  301.   * Sets up the DBlist object so that it can query the db
  302.   *
  303.   * @return DBList query ready to run
  304.   */
  305.   function _getDataList($report) {
  306.     $this->_export = $this->typelist->types[$report];
  307.     $start = $this->_daterange->getStart();
  308.     $stop  = clone($this->_daterange->getStop());
  309.     $stop->addDays(1);
  310.  
  311.     if (is_array($this->_export->union) && count($this->_export->union)) {
  312.       $union = array();
  313.       $limitsOffset = 0;
  314.       foreach ($this->_export->union as $export) {
  315.         $union[] = $this->_getDBListFromExport($export, $start, $stop, $limitsOffset);
  316.         $limitsOffset += count($export->limitation);
  317.       }
  318.       $list = $this->_getDBListFromExport($this->_export, $start, $stop);
  319.       $list->union = $union;
  320.     } else {
  321.       $list = $this->_getDBListFromExport($this->_export, $start, $stop);
  322.     }
  323.     return $list;
  324.   }
  325.  
  326.   /**
  327.   * From the export definition in the ExportType generate a DBList query
  328.   *
  329.   * @return void DBList ready for query
  330.   */
  331.   function _getDBListFromExport(&$export, $start, $stop, $limitsOffset=0) {
  332.     $where = $export->where;
  333.     $where[] = $export->timewhere[0].qw($start->dateTimeString());
  334.     $where[] = $export->timewhere[1].qw($stop->dateTimeString());
  335.     $where = array_merge($where, $this->_limitationSet($export->limitation, $limitsOffset));
  336.     // work out what view/pivot of the data we want to see
  337.     if (count($export->limitation) > 1 && is_array($export->pivot)) {
  338.       $pivot = $export->pivot[$this->PD['pivot']];
  339.       $export->group      = $pivot['group'];
  340.       $export->omitFields = array_flip($pivot['omitFields']);
  341.       $export->breakField = $pivot['breakField'];
  342.       if (isset($pivot['fieldOrder']) && is_array($pivot['fieldOrder'])) {
  343.         $export->fieldOrder = $pivot['fieldOrder'];
  344.       }
  345.       if (isset($pivot['extraFields']) && is_array($pivot['extraFields'])) {
  346.         $export->fields = array_merge($export->fields, $pivot['extraFields']);
  347.       }
  348.     }
  349.     $list = new DBList($export->basetable, $export->fields, join($where, ' AND '));
  350.     $list->join        = array_merge($list->join, $export->join);
  351.     $list->group       = $export->group;
  352.     $list->manualGroup = $export->manualGroup;
  353.     $list->manualSum   = $export->manualSum;
  354.     $list->order       = $export->order;
  355.     $list->distinct    = $export->distinct;
  356.     $list->fieldOrder  = $export->fieldOrder;
  357.     $list->breakfield  = $export->breakField;
  358.     if ($this->format & EXPORT_FORMAT_USEARRAY) {
  359.       $list->omitFields = $export->omitFields;
  360.     }
  361.     return $list;
  362.   }
  363.  
  364.   /**
  365.   * Determine what limitation should be applied to the broad query
  366.   *
  367.   * @todo //TODO:   there are limitations in the IN() syntax.... replace this with lots of booleans?
  368.   *
  369.   * @return array SQL field IN (list...) syntax
  370.   */
  371.   function _limitationSet($fields, $limitsOffset, $makeSQL=true) {
  372.     $sets = array();
  373.     for ($lim = 0; $lim < count($fields); $lim++) {
  374.       $limitation = array();
  375.       $fieldpattern = '/^limitation\-(\d+)\-(\d+)\-'.$fields[$lim].'$/';
  376.       $selected = array_values(preg_grep($fieldpattern, array_keys($this->PD)));
  377.       #preDump($selected);
  378.       for ($j=0; $j < count($selected); $j++) {
  379.         $ids = array();
  380.         preg_match($fieldpattern, $selected[$j], $ids);
  381.         $item = issetSet($this->PD,$selected[$j]);
  382.         if (issetSet($this->PD,'limitation-'.$ids[1].'-'.$ids[2].'-selected') && $item !== NULL) {
  383.           $limitation[] = /*$export->limitation[$lim].'.id='.*/qw($item);
  384.         }
  385.         //echo $namebase.':'.$j.':'.$lim.':'.$fields[$lim].':'.$item.'<br/>';
  386.       }
  387.       if (count($limitation)) {
  388.         if ($makeSQL) {
  389.           $sets[] = $fields[$lim].'.id IN ('.join($limitation, ', ').')';
  390.         } else {
  391.           $sets[$fields[$lim]] = $limitation;
  392.         }
  393.       }
  394.       //preDump($limitation);
  395.     }
  396.     return $sets;
  397.   }
  398.  
  399.   /**
  400.   * Set the filename and mimetype for the data export
  401.   *
  402.   * @return void nothing
  403.   */
  404.   function _getFilename() {
  405.     switch ($this->format & EXPORT_FORMAT_MASK) {
  406.       case EXPORT_FORMAT_CSV:
  407.         $ext = 'csv';
  408.         $type = 'text/csv';
  409.         break;
  410.       case EXPORT_FORMAT_TAB:
  411.         $ext = 'txt';
  412.         $type = 'text/tab-separated-values';
  413.         //$type = 'application/vnd-excel';
  414.         break;
  415.       case EXPORT_FORMAT_PDF:
  416.         $ext = 'pdf';
  417.         $type = 'application/pdf';
  418.         break;
  419.       default:
  420.         $ext = '';
  421.         $type = 'application/octet-stream';
  422.     }
  423.     $this->filename = parent::getFilename('export', $this->PD['what'], $ext);
  424.     $this->mimetype = $type;
  425.   }
  426.  
  427.   /**
  428.   * Generate the PDF for return to the user
  429.   *
  430.   * @uses PDFExport but only loaded here so that optional library can be absent without compile errors
  431.   * @return string $pdf containing the PDF
  432.   */
  433.   function _preparePDFExport(&$exportArray) {
  434.     require_once('inc/export/pdfexport.php');
  435.     $pdf = new PDFExport($exportArray);
  436.     return $pdf;
  437.   }
  438.  
  439.   /**
  440.   * Generate the standard report header from the date range and the description in ExportType
  441.   *
  442.   * @return string the title to be used for this report
  443.   */
  444.   function _reportHeader() {
  445.     $start = $this->_daterange->getStart();
  446.     $stop  = $this->_daterange->getStop();
  447.     $s = sprintf($this->_export->header, $start->getShortDateString(), $stop->getShortDateString());
  448.     return $s;
  449.   }
  450.  
  451. }  //ActionExport
  452. ?>

Documentation generated on Tue, 06 Mar 2007 10:01:25 +0000 by phpDocumentor 1.3.0