b2evolution

Multilingual multiuser multiblog engine

b2evolution Technical Documentation (Version 1.9) [ class tree: evocore ] [ index: evocore ] [ all elements ]

Source for file _itemquery.class.php

Documentation is available at _itemquery.class.php

  1. <?php
  2. /**
  3.  * This file implements the ItemQuery class.
  4.  *
  5.  * This file is part of the evoCore framework - {@link http://evocore.net/}
  6.  * See also {@link http://sourceforge.net/projects/evocms/}.
  7.  *
  8.  * @copyright (c)2003-2006 by Francois PLANQUE - {@link http://fplanque.net/}
  9.  *
  10.  *  {@internal License choice
  11.  *  - If you have received this file as part of a package, please find the license.txt file in
  12.  *    the same folder or the closest folder above for complete license terms.
  13.  *  - If you have received this file individually (e-g: from http://cvs.sourceforge.net/viewcvs.py/evocms/)
  14.  *    then you must choose one of the following licenses before using the file:
  15.  *    - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  16.  *    - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  17.  *  }}}
  18.  *
  19.  *  {@internal Open Source relicensing agreement:
  20.  *  }}}
  21.  *
  22.  * @package evocore
  23.  *
  24.  *  {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  25.  * @author fplanque: Francois PLANQUE.
  26.  *
  27.  * @version $Id: _itemquery.class.php,v 1.7.2.4 2007/01/30 20:15:13 blueyed Exp $
  28.  */
  29. if!defined('EVO_MAIN_INIT') ) die'Please, do not access this page directly.' );
  30.  
  31. /**
  32.  * Includes:
  33.  */
  34. require_once dirname(__FILE__).'/../../_misc/_sql.class.php';
  35.  
  36.  
  37. /**
  38.  * ItemQuery: help constructing queries on Items
  39.  */
  40. class ItemQuery extends SQL
  41. {
  42.     var $p;
  43.     var $title;
  44.     var $blog;
  45.     var $cat;
  46.     var $catsel;
  47.     var $show_statuses;
  48.     var $author;
  49.     var $assignees;
  50.     var $statuses;
  51.     var $dstart;
  52.     var $dstop;
  53.     var $timestamp_min;
  54.     var $timestamp_max;
  55.     var $keywords;
  56.     var $phrase;
  57.     var $exact;
  58.  
  59.  
  60.     /**
  61.      * Constructor.
  62.      *
  63.      * @param string Name of table in database
  64.      * @param string Prefix of fields in the table
  65.      * @param string Name of the ID field (including prefix)
  66.      */
  67.     function ItemQuery$dbtablename$dbprefix ''$dbIDname )
  68.     {
  69.         $this->dbtablename $dbtablename;
  70.         $this->dbprefix $dbprefix;
  71.         $this->dbIDname $dbIDname;
  72.  
  73.         $this->FROM$this->dbtablename.' INNER JOIN T_postcats ON '.$this->dbIDname.' = postcat_post_ID
  74.                                     INNER JOIN T_categories ON postcat_cat_ID = cat_ID ' );
  75.     }
  76.  
  77.  
  78.   /**
  79.      * Restrict to a specific post
  80.      */
  81.     function where_ID$p ''$title '' )
  82.     {
  83.         $r false;
  84.  
  85.         $this->p = $p;
  86.         $this->title = $title;
  87.  
  88.         // if a post number is specified, load that post
  89.         if!empty($p) )
  90.         {
  91.             $this->WHERE_and$this->dbIDname.' = 'intval($p) );
  92.             $r true;
  93.         }
  94.  
  95.         // if a post urltitle is specified, load that post
  96.         if!empty$title ) )
  97.         {
  98.             global $DB;
  99.             $this->WHERE_and$this->dbprefix.'urltitle = '.$DB->quote($title) );
  100.             $r true;
  101.         }
  102.  
  103.         return $r;
  104.     }
  105.  
  106.  
  107.   /**
  108.      * Restrict to specific collection/chapters (blog/categories)
  109.      *
  110.      * @todo get rid of blog #1
  111.      *
  112.      * @param integer 
  113.      * @param string List of cats to restrict to
  114.      * @param array Array of cats to restrict to
  115.      */
  116.     function where_chapter$blog$cat ''$catsel array() )
  117.     {
  118.         global $cat_array// this is required for the cat_req() callback in compile_cat_array()
  119.  
  120.         $blog intval($blog);    // Extra security
  121.  
  122.         // Save for future use (permission checks..)
  123.         $this->blog = $blog;
  124.  
  125.         if$blog != )
  126.         // Not Special case where we aggregate all blogs
  127.             $this->WHERE_and'cat_blog_ID = '$blog );
  128.         }
  129.  
  130.         $cat_array NULL;
  131.         $cat_modifier NULL;
  132.  
  133.         // Compile the real category list to use:
  134.         // TODO: allow to pass the compiled vars directly to this class
  135.         compile_cat_array$cat$catsel/* by ref */ $cat_array/* by ref */ $cat_modifier$blog == $blog );
  136.  
  137.         ifempty($cat_array) )
  138.         {    // We want to restict to some cats:
  139.             if$cat_modifier == '-' )
  140.             {
  141.                 $eq 'NOT IN';
  142.             }
  143.             else
  144.             {
  145.                 $eq 'IN';
  146.             }
  147.             $whichcat 'postcat_cat_ID '$eq.' ('.implode(','$cat_array)') ';
  148.  
  149.             // echo $whichcat;
  150.             $this->WHERE_and$whichcat );
  151.  
  152.            if$cat_modifier == '*' )
  153.             // We want the categories combined! (i-e posts must be in ALL requested cats)
  154.                 $this->GROUP_BY$this->dbIDname.' HAVING COUNT(postcat_cat_ID) = '.count($cat_array) );
  155.             }
  156.         }
  157.     }
  158.  
  159.  
  160.   /**
  161.      * Restrict to specific collection/chapters (blog/categories)
  162.      *
  163.      * @todo get rid of blog #1
  164.      *
  165.      * @param integer 
  166.      */
  167.     function where_chapter2$blog_ID$cat_array$cat_modifier )
  168.     {
  169.         // Save for future use (permission checks..)
  170.         $this->blog = $blog_ID;
  171.  
  172.         if$blog_ID != )
  173.         // Not Special case where we aggregate all blogs
  174.             $this->WHERE_and'cat_blog_ID = '.$blog_ID );
  175.         }
  176.  
  177.  
  178.         ifempty($cat_array) )
  179.         {    // We want to restict to some cats:
  180.             if$cat_modifier == '-' )
  181.             {
  182.                 $eq 'NOT IN';
  183.             }
  184.             else
  185.             {
  186.                 $eq 'IN';
  187.             }
  188.             $whichcat 'postcat_cat_ID '$eq.' ('.implode(','$cat_array)') ';
  189.  
  190.             // echo $whichcat;
  191.             $this->WHERE_and$whichcat );
  192.  
  193.            if$cat_modifier == '*' )
  194.             // We want the categories combined! (i-e posts must be in ALL requested cats)
  195.                 $this->GROUP_BY$this->dbIDname.' HAVING COUNT(postcat_cat_ID) = '.count($cat_array) );
  196.             }
  197.         }
  198.     }
  199.  
  200.  
  201.   /**
  202.      * Restrict to the visibility/sharing statuses we want to show
  203.      *
  204.      * @param array Restrict to these statuses
  205.      */
  206.     function where_visibility$show_statuses )
  207.     {
  208.         $this->show_statuses = $show_statuses;
  209.  
  210.         if!isset$this->blog ) )
  211.         {
  212.             debug_die'Status restriction requires to work with aspecific blog first.' );
  213.         }
  214.  
  215.         $this->WHERE_andstatuses_where_clause$show_statuses$this->dbprefix$this->blog ) );
  216.     }
  217.  
  218.  
  219.   /**
  220.      * Restrict to specific authors
  221.      *
  222.      * @param string List of authors to restrict to (must have been previously validated)
  223.      */
  224.     function where_author$author )
  225.     {
  226.         $this->author = $author;
  227.  
  228.         ifempty$author ) )
  229.         {
  230.             return;
  231.         }
  232.  
  233.         ifsubstr$author0== '-' )
  234.         {    // List starts with MINUS sign:
  235.             $eq 'NOT IN';
  236.             $author_list substr$author);
  237.         }
  238.         else
  239.         {
  240.             $eq 'IN';
  241.             $author_list $author;
  242.         }
  243.  
  244.         $this->WHERE_and$this->dbprefix.'creator_user_ID '.$eq.' ('.$author_list.')' );
  245.     }
  246.  
  247.  
  248.   /**
  249.      * Restrict to specific assignees
  250.      *
  251.      * @param string List of assignees to restrict to (must have been previously validated)
  252.      */
  253.     function where_assignees$assignees )
  254.     {
  255.         $this->assignees = $assignees;
  256.  
  257.         ifempty$assignees ) )
  258.         {
  259.             return;
  260.         }
  261.  
  262.         if$assignees == '-' )
  263.         {    // List is ONLY a MINUS sign (we want only those not assigned)
  264.             $this->WHERE_and$this->dbprefix.'assigned_user_ID IS NULL' );
  265.         }
  266.         elseifsubstr$assignees0== '-' )
  267.         {    // List starts with MINUS sign:
  268.             $this->WHERE_and'( '.$this->dbprefix.'assigned_user_ID IS NULL
  269.                               OR '.$this->dbprefix.'assigned_user_ID NOT IN ('.substr$assignees).') )' );
  270.         }
  271.         else
  272.         {
  273.             $this->WHERE_and$this->dbprefix.'assigned_user_ID IN ('.$assignees.')' );
  274.         }
  275.     }
  276.  
  277.  
  278.   /**
  279.      * Restrict to specific assignee or author
  280.      *
  281.      * @param integer assignee or author to restrict to (must have been previously validated)
  282.      */
  283.     function where_author_assignee$author_assignee )
  284.     {
  285.         $this->author_assignee $author_assignee;
  286.  
  287.         ifempty$author_assignee ) )
  288.         {
  289.             return;
  290.         }
  291.  
  292.         $this->WHERE_and'( '.$this->dbprefix.'creator_user_ID = '$author_assignee.' OR '.
  293.                                             $this->dbprefix.'assigned_user_ID = '.$author_assignee.' )' );
  294.     }
  295.  
  296.  
  297.   /**
  298.      * Restrict to specific (exetnded) statuses
  299.      *
  300.      * @param string List of assignees to restrict to (must have been previously validated)
  301.      */
  302.     function where_statuses$statuses )
  303.     {
  304.         $this->statuses = $statuses;
  305.  
  306.         ifempty$statuses ) )
  307.         {
  308.             return;
  309.         }
  310.  
  311.         if$statuses == '-' )
  312.         {    // List is ONLY a MINUS sign (we want only those not assigned)
  313.             $this->WHERE_and$this->dbprefix.'pst_ID IS NULL' );
  314.         }
  315.         elseifsubstr$statuses0== '-' )
  316.         {    // List starts with MINUS sign:
  317.             $this->WHERE_and'( '.$this->dbprefix.'pst_ID IS NULL
  318.                               OR '.$this->dbprefix.'pst_ID NOT IN ('.substr$statuses).') )' );
  319.         }
  320.         else
  321.         {
  322.             $this->WHERE_and$this->dbprefix.'pst_ID IN ('.$statuses.')' );
  323.         }
  324.     }
  325.  
  326.  
  327.     /**
  328.      * Restricts to a specific date range. (despite thje 'start' in the name
  329.      *
  330.      * Priorities:
  331.    *  -dstart and/or dstop
  332.    *  -week + m
  333.    *  -m
  334.    * @todo  -dstart + x days
  335.    * @see ItemList2::get_advertised_start_date()
  336.      *
  337.       * @param string YYYYMMDDHHMMSS (everything after YYYY is optional) or ''
  338.      * @param integer week number or ''
  339.      * @param string YYYYMMDDHHMMSS to start at, '' for first available
  340.      * @param string YYYYMMDDHHMMSS to stop at
  341.      * @param mixed Do not show posts before this timestamp, can be 'now'
  342.      * @param mixed Do not show posts after this timestamp, can be 'now'
  343.      */
  344.     function where_datestart$m ''$w ''$dstart ''$dstop ''$timestamp_min ''$timestamp_max 'now' )
  345.     {
  346.         global $time_difference;
  347.  
  348.         $this->$m;
  349.         $this->$w;
  350.         $this->dstart = $dstart;
  351.         $this->dstop = $dstop;
  352.         $this->timestamp_min = $timestamp_min;
  353.         $this->timestamp_max = $timestamp_max;
  354.  
  355.  
  356.         $start_is_set false;
  357.         $stop_is_set false;
  358.  
  359.  
  360.         // if a start date is specified in the querystring, crop anything before
  361.         if!empty($dstart) )
  362.         {
  363.             // Add trailing 0s: YYYYMMDDHHMMSS
  364.             $dstart0 $dstart.'00000000000000';  // TODO: this is NOT correct, should be 0101 for month
  365.  
  366.             $dstart_mysql substr($dstart0,0,4).'-'.substr($dstart0,4,2).'-'.substr($dstart0,6,2).' '
  367.                                             .substr($dstart0,8,2).':'.substr($dstart0,10,2).':'.substr($dstart0,12,2);
  368.  
  369.             $this->WHERE_and$this->dbprefix.'datestart >= \''.$dstart_mysql.'\'
  370.                                                     OR ( '.$this->dbprefix.'datedeadline IS NULL AND '.$this->dbprefix.'datestart >= \''.$dstart_mysql.'\' )' );
  371.  
  372.             $start_is_set true;
  373.         }
  374.  
  375.  
  376.         // if a stop date is specified in the querystring, crop anything before
  377.         if!empty($dstop) )
  378.         {
  379.             switchstrlen$dstop ) )
  380.             {
  381.                 case '4':
  382.                     // We have only year, add one to year
  383.                     $dstop_mysql ($dstop+1).'-01-01 00:00:00';
  384.                     break;
  385.  
  386.                 case '6':
  387.                     // We have year month, add one to month
  388.                     $dstop_mysql date("Y-m-d H:i:s "mktime(000substr($dstop,4,2)+101substr($dstop,0,4)));
  389.                     break;
  390.  
  391.                 case '8':
  392.                     // We have year mounth day, add one to day
  393.                     $dstop_mysql date("Y-m-d H:i:s "mktime(000substr($dstop,4,2)(substr($dstop,6,2)substr($dstop,0,4)));
  394.                     break;
  395.  
  396.                 case '10':
  397.                     // We have year mounth day hour, add one to hour
  398.                     $dstop_mysql date("Y-m-d H:i:s "mktime( ( substr($dstop,8,2)00substr($dstop,4,2)substr($dstop,6,2)substr($dstop,0,4)));
  399.                     break;
  400.  
  401.                 case '12':
  402.                     // We have year mounth day hour minute, add one to minute
  403.                     $dstop_mysql date("Y-m-d H:i:s "mktimesubstr($dstop,8,2)substr($dstop,8,2)0substr($dstop,4,2)substr($dstop,6,2)substr($dstop,0,4)));
  404.                     break;
  405.  
  406.                 default:
  407.                     // add one to second
  408.                     $dstop_mysql substr($dstop,0,4).'-'.substr($dstop,4,2).'-'.substr($dstop,6,2).' '
  409.                                             .substr($dstop,8,2).':'.substr($dstop,10,2).':'.substr$dstop,12,2);
  410.             }
  411.  
  412.             $this->WHERE_and$this->dbprefix.'datestart < \''.$dstop_mysql.'\'' )// NOT <= comparator because we compare to the superior stop date
  413.  
  414.             $stop_is_set true;
  415.         }
  416.  
  417.         if!$start_is_set || !$stop_is_set )
  418.         {
  419.             if!is_null($w&& $w >= // Note: week # can be 0
  420.                     && strlen($m== )
  421.             // If a week number is specified (with a year)
  422.  
  423.                 // Note: we use PHP to calculate week boundaries in order to handle weeks
  424.                 // that overlap 2 years properly, even when start on week is monday (which MYSQL won't handle properly)
  425.                 $start_date_for_week get_start_date_for_week$m$wlocale_startofweek() );
  426.  
  427.                 $this->WHERE_and$this->dbprefix.'datestart >= "'.date('Y-m-d',$start_date_for_week).'"' );
  428.                 $this->WHERE_and$this->dbprefix.'datestart < "'.date('Y-m-d',$start_date_for_week+604800 ).'"' )// + 7 days
  429.  
  430.                 $start_is_set true;
  431.                 $stop_is_set true;
  432.             }
  433.             elseif!empty($m) )
  434.             {    // We want to restrict on an interval:
  435.                 $this->WHERE_and'YEAR('.$this->dbprefix.'datestart)='.intval(substr($m,0,4)) );
  436.                 ifstrlen($m)
  437.                     $this->WHERE_and'MONTH('.$this->dbprefix.'datestart)='.intval(substr($m,4,2)) );
  438.                 ifstrlen($m)
  439.                     $this->WHERE_and'DAYOFMONTH('.$this->dbprefix.'datestart)='.intval(substr($m,6,2)) );
  440.                 ifstrlen($m)
  441.                     $this->WHERE_and'HOUR('.$this->dbprefix.'datestart)='.intval(substr($m,8,2)) );
  442.                 ifstrlen($m11 )
  443.                     $this->WHERE_and'MINUTE('.$this->dbprefix.'datestart)='.intval(substr($m,10,2)) );
  444.                 ifstrlen($m13 )
  445.                     $this->WHERE_and'SECOND('.$this->dbprefix.'datestart)='.intval(substr($m,12,2)) );
  446.  
  447.                 $start_is_set true;
  448.                 $stop_is_set true;
  449.             }
  450.  
  451.         }
  452.  
  453.  
  454.         // TODO: start + x days
  455.         // TODO: stop - x days
  456.  
  457.  
  458.         // SILENT limits!
  459.  
  460.         // Timestamp limits:
  461.         if$timestamp_min == 'now' )
  462.         {
  463.             // echo 'hide past';
  464.             $timestamp_min time();
  465.         }
  466.         if!empty($timestamp_min) )
  467.         // Hide posts before
  468.             // echo 'hide before '.$timestamp_min;
  469.             $date_min date('Y-m-d H:i:s'$timestamp_min $time_difference );
  470.             $this->WHERE_and$this->dbprefix.'datestart >= \''$date_min.'\'' );
  471.         }
  472.  
  473.         if$timestamp_max == 'now' )
  474.         {
  475.             // echo 'hide future';
  476.             $timestamp_max time();
  477.         }
  478.         if!empty($timestamp_max) )
  479.         // Hide posts after
  480.             // echo 'after';
  481.             $date_max date('Y-m-d H:i:s'$timestamp_max $time_difference );
  482.             $this->WHERE_and$this->dbprefix.'datestart <= \''$date_max.'\'' );
  483.         }
  484.  
  485.     }
  486.  
  487.  
  488.   /**
  489.      * Restrict with keywords
  490.      *
  491.      * @param string Keyword search string
  492.      * @param mixed Search for entire phrase or for individual words
  493.      * @param mixed Require exact match of title or contents
  494.      */
  495.     function where_keywords$keywords$phrase$exact )
  496.     {
  497.         global $DB;
  498.  
  499.         $this->keywords = $keywords;
  500.         $this->phrase = $phrase;
  501.         $this->exact = $exact;
  502.  
  503.         ifempty($keywords) )
  504.         {
  505.             return;
  506.         }
  507.  
  508.         $search '';
  509.  
  510.         if$exact )
  511.         {    // We want exact match of title or contents
  512.             $n '';
  513.         }
  514.         else
  515.         // The words/sentence are/is to be included in in the title or the contents
  516.             $n '%';
  517.         }
  518.  
  519.         if( ($phrase == '1'or ($phrase == 'sentence') )
  520.         // Sentence search
  521.             $keywords $DB->escape(trim($keywords));
  522.             $search .= '('.$this->dbprefix.'title LIKE \''$n$keywords$n'\') OR ('.$this->dbprefix.'content LIKE \''$n$keywords$n.'\')';
  523.         }
  524.         else
  525.         // Word search
  526.             ifstrtoupper$phrase == 'OR' )
  527.                 $swords 'OR';
  528.             else
  529.                 $swords 'AND';
  530.  
  531.             // puts spaces instead of commas
  532.             $keywords preg_replace('/, +/'''$keywords);
  533.             $keywords str_replace(','' '$keywords);
  534.             $keywords str_replace('"'' '$keywords);
  535.             $keywords trim($keywords);
  536.             $keyword_array explode(' ',$keywords);
  537.             $join '';
  538.             for $i 0$i count($keyword_array)$i++)
  539.             {
  540.                 $search .= ' '$join' ( ('.$this->dbprefix.'title LIKE \''$n$DB->escape($keyword_array[$i])$n'\')
  541.                                                                 OR ('.$this->dbprefix.'content LIKE \''$n$DB->escape($keyword_array[$i])$n.'\') ) ';
  542.                 $join $swords;
  543.             }
  544.         }
  545.  
  546.         //echo $search;
  547.         $this->WHERE_and$search );
  548.     }
  549.  
  550.  
  551. }
  552.  
  553. /*
  554.  * $Log: _itemquery.class.php,v $
  555.  * Revision 1.7.2.4  2007/01/30 20:15:13  blueyed
  556.  * MFH: Fixed inclusion of sub-categories in item list (e.g. ?cat=1)
  557.  *
  558.  * Revision 1.7.2.3  2006/11/21 17:43:40  fplanque
  559.  * Fixed displaying of yearly archives
  560.  *
  561.  * Revision 1.7.2.2  2006/11/04 19:54:54  fplanque
  562.  * Reinjected old Log blocks. Removing them from CVS was a bad idea -- especially since Daniel has decided branch 1.9 was his HEAD...
  563.  *
  564.  * Revision 1.7  2006/07/02 21:53:31  blueyed
  565.  * time difference as seconds instead of hours; validate user#1 on upgrade; bumped new_db_version to 9300.
  566.  *
  567.  * Revision 1.6  2006/06/19 20:59:37  fplanque
  568.  * noone should die anonymously...
  569.  *
  570.  * Revision 1.5  2006/06/19 16:58:11  fplanque
  571.  * minor
  572.  *
  573.  * Revision 1.4  2006/06/13 21:49:15  blueyed
  574.  * Merged from 1.8 branch
  575.  *
  576.  * Revision 1.3  2006/04/19 20:13:50  fplanque
  577.  * do not restrict to :// (does not catch subdomains, not even www.)
  578.  *
  579.  * Revision 1.2  2006/03/12 23:08:59  fplanque
  580.  * doc cleanup
  581.  *
  582.  * Revision 1.1  2006/02/23 21:11:58  fplanque
  583.  * File reorganization to MVC (Model View Controller) architecture.
  584.  * See index.hml files in folders.
  585.  * (Sorry for all the remaining bugs induced by the reorg... :/)
  586.  *
  587.  * Revision 1.12  2006/02/10 22:08:07  fplanque
  588.  * Various small fixes
  589.  *
  590.  * Revision 1.11  2006/02/03 21:58:05  fplanque
  591.  * Too many merges, too little time. I can hardly keep up. I'll try to check/debug/fine tune next week...
  592.  *
  593.  * Revision 1.10  2006/01/04 20:34:52  fplanque
  594.  * allow filtering on extra statuses
  595.  *
  596.  * Revision 1.9  2006/01/04 19:07:48  fplanque
  597.  * allow filtering on assignees
  598.  *
  599.  * Revision 1.8  2005/12/21 20:39:04  fplanque
  600.  * minor
  601.  *
  602.  * Revision 1.7  2005/12/19 19:30:14  fplanque
  603.  * minor
  604.  *
  605.  * Revision 1.6  2005/12/19 18:10:18  fplanque
  606.  * Normalized the exp and tracker tabs.
  607.  *
  608.  * Revision 1.5  2005/12/05 18:17:19  fplanque
  609.  * Added new browsing features for the Tracker Use Case.
  610.  *
  611.  * Revision 1.4  2005/09/06 19:38:29  fplanque
  612.  * bugfixes
  613.  *
  614.  * Revision 1.3  2005/09/06 17:13:55  fplanque
  615.  * stop processing early if referer spam has been detected
  616.  *
  617.  * Revision 1.2  2005/09/01 17:11:46  fplanque
  618.  * no message
  619.  *
  620.  * Revision 1.1  2005/08/31 19:08:51  fplanque
  621.  * Factorized Item query WHERE clause.
  622.  * Fixed calendar contextual accuracy.
  623.  *
  624.  */
  625. ?>

Documentation generated on Tue, 18 Dec 2007 22:47:34 +0100 by phpDocumentor 1.4.0