Source for file SqlRecordset.php

Documentation is available at SqlRecordset.php

  1. <?php
  2.     /**
  3.      * SQL Recordset Class
  4.      *
  5.      * @copyright Copyright (c) 2003-2006 Mirchev Ideas Ltd. All rights reserved.
  6.      * @package MIPHPF
  7.      */
  8.     
  9.     /**
  10.      * Handle and manage the reading of data from database.
  11.      * This class only read data from a given database table with necessary
  12.      * ordering and filtering.
  13.      *
  14.      * @copyright Copyright (c) 2003-2006 Mirchev Ideas Ltd. All rights reserved.
  15.      * @package MIPHPF
  16.      */    
  17.     class miSqlRecordset {
  18.         
  19.         
  20.         /**
  21.          * @access protected
  22.          */
  23.         protected $_table;
  24.         
  25.         /**
  26.          * @access protected
  27.          */
  28.         protected $_firstRecordIndex = 0;
  29.         
  30.         /**
  31.          * @access protected
  32.          */
  33.         protected $_numRecords = false;
  34.         
  35.         /**
  36.          * @access protected
  37.          */
  38.         protected $_sortBy = '';
  39.         
  40.         /**
  41.          * @access protected
  42.          */
  43.         protected $_sortDir = '';
  44.         
  45.         /**
  46.          * @access protected
  47.          */
  48.         protected $_groupBy = '';
  49.         
  50.         /**
  51.          * @access protected
  52.          */
  53.         protected $_filters = array();
  54.         
  55.         /**
  56.          * @access protected
  57.          */
  58.         protected $_havingFilterNames = array();
  59.         
  60.         /**
  61.          * @access protected
  62.          */
  63.         protected $_allFields = null;
  64.         
  65.         /**
  66.          * @access protected
  67.          */
  68.         protected $_selectFields = array();
  69.         
  70.         /**
  71.          * @access protected
  72.          */
  73.         protected $_selectedFields = array();
  74.         
  75.         /**
  76.          * @access protected
  77.          */
  78.         protected $_joinConditions = array();
  79.         
  80.         
  81.         /**
  82.          * miSqlRecordset constructor
  83.          * 
  84.          * Example:
  85.          * <code>
  86.          * <?php
  87.          * $recordset = new miSqlRecordset('tableName');
  88.          * ?>
  89.          * <?php
  90.          * $recordset = new miSqlRecordset(array('firstTable', 'secondTable'));
  91.          * ?>
  92.          * </code>
  93.          * 
  94.          * @access public
  95.          * @param string|array$table database table name, or several table names
  96.          */
  97.         public function __construct($table)
  98.         {
  99.             $this->_table = $table;
  100.         }
  101.         
  102.         /**
  103.          * Adds join condition
  104.          * 
  105.          * @param string $joinType the type of the join, eg. INNER, LEFT
  106.          * @param string $joinTable the table to be joined
  107.          * @param string $joinCondition the condition of the join
  108.          */
  109.         public function addJoinCondition($joinType$joinTable$joinCondition)
  110.         {
  111.             $this->_joinConditions[array($joinType$joinTable$joinCondition);
  112.         }
  113.         
  114.         /**
  115.          * Sets the field by which the result of the query will be ordered and
  116.          * the direction of ordering - ascending or descending.
  117.          * 
  118.          * Example:
  119.          * <code>
  120.          * <?php
  121.          * $recordset = new miSqlRecordset('tableName');
  122.          * $recordset->setOrder($tableField, 'ASC');
  123.          * ?>
  124.          * </code>
  125.          * 
  126.          * @access public
  127.          * @param string $sortBy database table field name
  128.          * @param string $sortDir direction of ordering - ascending or descending
  129.          */
  130.         public function setOrder($sortBy$sortDir)
  131.         {
  132.             $this->_sortBy = $sortBy;
  133.             $this->_sortDir = $sortDir;
  134.         }
  135.         
  136.         
  137.         /**
  138.          * Sets group by fields
  139.          * The param is directly added after the GROUP BY clause
  140.          * 
  141.          * @param string the group by fields
  142.          */
  143.         public function setGroupBy($groupBy)
  144.         {
  145.             $this->_groupBy = $groupBy;
  146.         }
  147.         
  148.         /**
  149.          * Adds a filter object
  150.          * 
  151.          * Example:
  152.          * <code>
  153.          * <?php
  154.          * $recordset = new miSqlRecordset('tableName');
  155.          * $recordset->addFilter($filter);
  156.          * ?>
  157.          * </code>
  158.          * 
  159.          * @access public
  160.          * @param array $filter a filter object
  161.          */
  162.         public function addFilter(miSqlFilter $filter)
  163.         {
  164.             $this->_filters[$filter;
  165.         }
  166.         
  167.         /**
  168.          * Adds multiple filters
  169.          * 
  170.          * @access public
  171.          * @param array $filters array of filter objects
  172.          */
  173.         public function addFilters($filters)
  174.         {
  175.             $this->_filters = array_merge($this->_filters$filters);
  176.         }
  177.  
  178.         /**
  179.          * Sets the names of the filters to be used in a HAVING clause instead of WHERE
  180.          * 
  181.          * @access public
  182.          * @param array $filterNames array of filter names to be used in a HAVING clause instead of WHERE
  183.          */
  184.         function setHavingFilterNames($filterNames)
  185.         {
  186.             $this->_havingFilterNames = $filterNames;
  187.         }
  188.         
  189.         /**
  190.          * Sets the select fields
  191.          * Defaults to * (all columns)
  192.          * 
  193.          * @access public
  194.          * @param array $fields 
  195.          */
  196.         public function setSelectFields($selectFields)
  197.         {
  198.             $this->_selectFields = $selectFields;
  199.         }
  200.         
  201.         /**
  202.          * Sets how many rows to be read from the databse
  203.          * 
  204.          * Example:
  205.          * <code>
  206.          * <?php
  207.          * $recordset = new miSqlRecordset('tableName');
  208.          * $recordset->setRecordsLimit(5, 20);
  209.          * ?>
  210.          * </code>
  211.          * 
  212.          * @access public
  213.          * @param int $from from which record index to start
  214.          * @param int $num how many rows to read
  215.          */
  216.         public function setRecordsLimit($from$num)
  217.         {
  218.             $this->_firstRecordIndex = $from;
  219.             $this->_numRecords = $num;
  220.         }
  221.         
  222.         
  223.         /**
  224.          * Return the order clause
  225.          *
  226.          * Example:
  227.          * <code>
  228.          * <?php
  229.          * $recordset = new miSqlRecordset('tableName');
  230.          * $recordset->setOrder($tableField, 'ASC');
  231.          * $order = $recordset->getSqlOrderClause();
  232.          * ?>
  233.          * </code>
  234.          *
  235.          * @access protected
  236.          * @return string order clause
  237.          */
  238.         protected function getSqlOrderClause()
  239.         {
  240.             if ($this->_sortBy == '')
  241.                 return '';
  242.             
  243.             $fields $this->getAllFields();
  244.             if (!in_array($this->_sortBy$fields))
  245.                 throw new miConfigurationException('Invalid sort column: ' $this->_sortBy);
  246.             if (($this->_sortDir != 'ASC'and ($this->_sortDir != 'DESC'and ($this->_sortDir != ''))
  247.                 throw new miConfigurationException('Invalid sort direction: ' $this->_sortDir);
  248.             
  249.             return ' ORDER BY ' $this->_sortBy . ' ' $this->_sortDir;
  250.         }
  251.         
  252.         
  253.         /**
  254.          * Return all the specified filter clauses as a string
  255.          *
  256.          * @access protected
  257.          * @return string all the specified filter clauses as a string
  258.          * @throws miConfigurationException
  259.          */
  260.         protected function getSqlFilterClause()
  261.         {
  262.             if (empty($this->_filters))
  263.                 return '';
  264.             
  265.             $filtersSql array();
  266.             $fields $this->getAllFields();
  267.             
  268.             foreach ($this->_filters as $filter{                
  269.                 
  270.                 if (in_array($filter->getName()$this->_havingFilterNames)) {
  271.                     continue;
  272.                 }
  273.  
  274.                 // Validate the filter fields
  275.                 $filterFields $filter->getSqlFields();
  276.                 foreach ($filterFields as $filterField{
  277.                     if (in_array($filterField$fields))
  278.                         continue;
  279.                     if (substr_compare($filterField$this->_table .  '.'0strlen($this->_table)+1== 0{
  280.                         if (in_array(substr($filterFieldstrlen($this->_table)+1)$fields))
  281.                             continue;
  282.                     }
  283.                     
  284.                     throw new miConfigurationException('Invalid filter field: ' $filterFieldmiConfigurationException::EXCEPTION_FILTER_INVALID_FIELD);
  285.                 }
  286.                 
  287.                 $sql $filter->getSql();
  288.                 if ($sql != '')
  289.                     $filtersSql[$sql;
  290.             }
  291.             return implode(' AND '$filtersSql);
  292.         }
  293.         
  294.         /**
  295.          * Return all the specified HAVING filter clauses as a string
  296.          *
  297.          * @access protected
  298.          * @return string all the specified HAVING filter clauses as a string
  299.          * @throws miConfigurationException
  300.          */
  301.         protected function getSqlFilterHavingClause()
  302.         {
  303.             if (empty($this->_filters))
  304.                 return '';
  305.             
  306.             $filtersSql array();
  307.             
  308.             foreach ($this->_filters as $filter{                
  309.                 
  310.                 if (!in_array($filter->getName()$this->_havingFilterNames)) {
  311.                     continue;
  312.                 }
  313.                 
  314.                 $sql $filter->getSql();
  315.                 if ($sql != '')
  316.                     $filtersSql[$sql;
  317.             }
  318.             return implode(' AND '$filtersSql);
  319.         }
  320.  
  321.  
  322.         /**
  323.          * Return the limit as a sql code
  324.          *
  325.          * @access protected
  326.          * @param int $fromIndex from which record index to start
  327.          * @param int $numRecords number of rows to be read
  328.          * @return string the limit as a sql code
  329.          */
  330.         protected function getSqlLimitClause($fromIndex$numRecords)
  331.         {
  332.             $fromIndex = (int)$fromIndex;
  333.             $numRecords = (int)$numRecords;
  334.             return ' LIMIT ' $fromIndex ',' $numRecords;
  335.         }
  336.         
  337.         /**
  338.          * Return the join conditions sql
  339.          *
  340.          * @access protected
  341.          * @return string the join conditions sql
  342.          */
  343.         protected function getJoinConditionsClause()
  344.         {
  345.             $sql '';
  346.             foreach ($this->_joinConditions as $joinCondition{
  347.                 $sql .= ' ' $joinCondition[0' JOIN ' $joinCondition[1' ' $joinCondition[2];
  348.             }
  349.             return $sql;
  350.         }
  351.         
  352.         /**
  353.          * Returns the table sql clause
  354.          * 
  355.          * @access protected
  356.          * @return string the table clause
  357.          */
  358.         protected function getTablesClause()
  359.         {
  360.             if (count($this->_joinConditions== 0)
  361.                 return ' FROM ' $this->_table;
  362.             
  363.             return ' FROM ' $this->_table . $this->getJoinConditionsClause();
  364.         }
  365.         
  366.         /**
  367.          * Returns the group by clause
  368.          * 
  369.          * @return string sql clause
  370.          */
  371.         protected function getGroupByClause()
  372.         {
  373.             if ($this->_groupBy != '')
  374.                 return ' GROUP BY ' $this->_groupBy;
  375.             return '';
  376.         }
  377.         
  378.         /**
  379.          * Returns the query to select all records for the recordset (without a LIMIT clause)
  380.          * 
  381.          * @return string sql clause
  382.          */
  383.         public function getSelectQuery()
  384.         {
  385.             $filterClause $this->getSqlFilterClause();
  386.             if ($filterClause != '')
  387.                 $filterClause ' WHERE ' $filterClause;
  388.                 
  389.             $filterHavingClause $this->getSqlFilterHavingClause();
  390.             if ($filterHavingClause != '')
  391.                 $filterHavingClause ' HAVING ' $filterHavingClause;            
  392.             
  393.             $fields (count($this->_selectFields0implode(','$this->_selectFields'*';
  394.             
  395.             $query 'SELECT ' $fields $this->getTablesClause(.
  396.                 $filterClause $this->getGroupByClause($filterHavingClause $this->getSqlOrderClause();
  397.             
  398.             return $query;
  399.         }
  400.         
  401.         /**
  402.          * Return the number of all rows in a database table that reply to the
  403.          * given filter clause
  404.          *
  405.          * Example:
  406.          * <code>
  407.          * <?php
  408.          * $recordset = new miSqlRecordset('tableName');
  409.          * $recordset->addFilter($arrayFilter);
  410.          * $count = $recordset->getRecordsCount();
  411.          * ?>
  412.          * </code>
  413.          *
  414.          * @access public
  415.          * @return int number of all rows in a database table
  416.          * @throws miDBException
  417.          */
  418.         public function getRecordsCount()
  419.         {
  420.             if (empty($this->_havingFilterNames)) {
  421.                 $filterClause $this->getSqlFilterClause();
  422.                 if ($filterClause != '')
  423.                     $filterClause ' WHERE ' $filterClause;
  424.                 
  425.                 $query 'SELECT COUNT(*) AS N ' $this->getTablesClause($filterClause  $this->getGroupByClause();                
  426.             else {
  427.                 // If there are fields for the HAVING clause, the only way to get the number of records is to execute the actual query as a subselect
  428.                 $query 'SELECT COUNT(*) AS N FROM ('.$this->getSelectQuery().') SubQuery';                
  429.             }
  430.             
  431.             $rows miStaticDBUtil::execSelect($query);
  432.             return (int)$rows[0]['N'];
  433.         }
  434.         
  435.         
  436.         /**
  437.          * Read rows from a database table.
  438.          * The result reply to the given filter clause and is returned in order
  439.          * specify by order clause
  440.          * 
  441.          * Example:
  442.          * <code>
  443.          * <?php
  444.          * $recordset = new miSqlRecordset('tableName');
  445.          * $recordset->setOrder($tableField, 'ASC');
  446.          * $recordset->addFilter($filter);
  447.          * $rows = $recordset->getRecords();
  448.          * ?>
  449.          * </code>
  450.          * 
  451.          * @access public
  452.          * @return array rows returned from database
  453.          * @throws miDBException
  454.          */
  455.         public function getRecords()
  456.         {
  457.             return $this->getRecordsByIndex($this->_firstRecordIndex$this->_numRecords);
  458.         }
  459.         
  460.         
  461.         /**
  462.          * Read fixed number of rows from a given index in a database table.
  463.          * The result reply to the given filter clause and is returned in order
  464.          * specify by order clause
  465.          * If both $fromIndex and $numRecords are false returns all records
  466.          * 
  467.          * Example:
  468.          * <code>
  469.          * <?php
  470.          * $recordset = new miSqlRecordset('tableName');
  471.          * $recordset->setOrder($tableField, 'ASC');
  472.          * $rows = $recordset->getRecordsByIndex($fromIndex, $numRecords);
  473.          * ?>
  474.          * </code>
  475.          * 
  476.          * @access public
  477.          * @param int $fromIndex from which record index to start
  478.          * @param int $numRecords number of rows to be read
  479.          * @return array rows returned from database
  480.          * @throws miDBException
  481.          */
  482.         public function getRecordsByIndex($fromIndex$numRecords)
  483.         {
  484.             $query $this->getSelectQuery();
  485.             
  486.             if (($fromIndex !== false&& ($numRecords !== false))
  487.                 $query .= $this->getSqlLimitClause($fromIndex$numRecords);
  488.             
  489.             return miStaticDBUtil::execSelectAndGetFields($query$this->_selectedFields);
  490.         }
  491.         
  492.         
  493.         /**
  494.          * Read all records from the database table
  495.          * The result is limited to the given filter clause and is returned in order
  496.          * specify by order clause
  497.          * 
  498.          * @access public
  499.          * @return array rows returned from database
  500.          * @throws miDBException
  501.          */
  502.         public function getAllRecords()
  503.         {
  504.             return $this->getRecordsByIndex(falsefalse);
  505.         }
  506.         
  507.         /**
  508.          * Returns the list of all selected fields
  509.          * An empty array is returned of no query has been executed
  510.          * 
  511.          * @access public
  512.          * @return array the selected field names
  513.          */
  514.         public function getSelectedFields()
  515.         {
  516.             return $this->_selectedFields;
  517.         }
  518.         
  519.         /**
  520.          * Returns all fields of the recordset table(s)
  521.          * The result of the function is cached. Call only after all join conditions have been added.
  522.          * 
  523.          * @access public
  524.          * @return array the field names
  525.          */
  526.         public function getAllFields()
  527.         {
  528.             if ($this->_allFields != null)
  529.                 return $this->_allFields;
  530.             
  531.             $tables array($this->_table);
  532.             foreach ($this->_joinConditions as $joinCondition)
  533.                 $tables[$joinCondition[1];
  534.             
  535.             $this->_allFields = $this->_havingFilterNames;
  536.             foreach ($tables as $table)
  537.                 $this->_allFields = array_merge($this->_allFieldsmiStaticDBUtil::getTableFields($table));
  538.             return $this->_allFields;
  539.         }
  540.         
  541.         /**
  542.          * Returns the table name for the current recordset
  543.          * 
  544.          * @access public
  545.          * @return string 
  546.          */
  547.         public function getTable()
  548.         {
  549.             return $this->_table;
  550.         }
  551.     }
  552. ?>

Documentation generated on Thu, 08 May 2008 16:57:38 +0300 by phpDocumentor 1.4.1