b2evolution PHP Cross Reference Blogging Systems

Source: /inc/items/model/_itemlight.class.php - 1350 lines - 37552 bytes - Summary - Text - Print

Description: This file implements the ItemLight class. This file is part of the evoCore framework - {@link http://evocore.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file implements the ItemLight 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-2014 by Francois Planque - {@link http://fplanque.com/}
   9   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  10   *
  11   * {@internal License choice
  12   * - If you have received this file as part of a package, please find the license.txt file in
  13   *   the same folder or the closest folder above for complete license terms.
  14   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  15   *   then you must choose one of the following licenses before using the file:
  16   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  17   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  18   * }}
  19   *
  20   * {@internal Open Source relicensing agreement:
  21   * Daniel HAHLER grants Francois PLANQUE the right to license
  22   * Daniel HAHLER's contributions to this file and the b2evolution project
  23   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  24   * }}
  25   *
  26   * @package evocore
  27   *
  28   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  29   * @author fplanque: Francois PLANQUE.
  30   *
  31   * @version $Id: _itemlight.class.php 6136 2014-03-08 07:59:48Z manuel $
  32   */
  33  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  34  
  35  load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
  36  
  37  
  38  /**
  39   * ItemLight Class
  40   *
  41   * Basically, all we want to achieve here is:
  42   * - permalinks
  43   * - last mod dates
  44   *
  45   * This object SHOULD NOT be saved.
  46   *
  47   * @package evocore
  48   */
  49  class ItemLight extends DataObject
  50  {
  51      /**
  52       * Publish date ("Y-m-d H:i:s"). This may be in the future.
  53       * This should get compared to {@link $localtimenow}.
  54       * @var string
  55       */
  56      var $issue_date;
  57  
  58      /**
  59       * Last modification date (timestamp)
  60       * This should get compared to {@link $localtimenow}.
  61       * @var integer
  62       */
  63      var $datemodified;
  64  
  65      var $title;
  66  
  67      var $excerpt;
  68  
  69      var $urltitle;
  70  
  71      var $canonical_slug_ID;
  72  
  73      var $tiny_slug_ID;
  74  
  75      /**
  76       * External URL the item links to (if any).
  77       * @var string
  78       */
  79      var $url;
  80  
  81       var $ptyp_ID;
  82  
  83      /**
  84       * ID of the main category.
  85       * Use {@link ItemLight::set()} to set it, since other vars get lazily derived from it.
  86       * @var integer
  87       */
  88      var $main_cat_ID = 0;
  89      /**
  90       * @var Chapter
  91       * @access protected
  92       * @see ItemLight::get_main_Chapter()
  93       */
  94      var $main_Chapter;
  95  
  96      /**
  97       * Derived from $main_cat_ID.
  98       *
  99       * @var integer
 100       * @access protected
 101       * @see ItemLight::get_blog_ID()
 102       */
 103      var $blog_ID;
 104  
 105      /**
 106       * The Blog of the Item (lazy filled, use {@link get_Blog()} to access it.
 107       * @access protected
 108       * @var Blog
 109       */
 110      var $Blog;
 111  
 112  
 113      /**
 114       * Constructor
 115       *
 116       * @param object table Database row
 117       * @param string
 118       * @param string
 119       * @param string
 120       * @param string for derived classes
 121       * @param string datetime field name
 122       * @param string datetime field name
 123       * @param string User ID field name
 124       * @param string User ID field name
 125       */
 126  	function ItemLight( $db_row = NULL, $dbtable = 'T_items__item', $dbprefix = 'post_', $dbIDname = 'post_ID', $objtype = 'ItemLight',
 127                     $datecreated_field = '', $datemodified_field = 'datemodified',
 128                     $creator_field = '', $lasteditor_field = '' )
 129      {
 130          global $localtimenow, $default_locale, $current_User;
 131  
 132          // Call parent constructor:
 133          parent::DataObject( $dbtable, $dbprefix, $dbIDname, $datecreated_field, $datemodified_field,
 134                                                  $creator_field, $lasteditor_field );
 135  
 136          $this->delete_restrictions = array(
 137                  array( 'table'=>'T_links', 'fk'=>'link_dest_itm_ID', 'msg'=>T_('%d links to source items') ),
 138                  array( 'table'=>'T_items__item', 'fk'=>'post_parent_ID', 'msg'=>T_('%d links to child items') ),
 139              );
 140  
 141          $this->delete_cascades = array(
 142                  array( 'table'=>'T_links', 'fk'=>'link_itm_ID', 'msg'=>T_('%d links to destination items') ),
 143                  array( 'table'=>'T_postcats', 'fk'=>'postcat_post_ID', 'msg'=>T_('%d links to extra categories') ),
 144                  array( 'table'=>'T_comments', 'fk'=>'comment_post_ID', 'msg'=>T_('%d comments') ),
 145                  array( 'table'=>'T_items__version', 'fk'=>'iver_itm_ID', 'msg'=>T_('%d versions') ),
 146                  array( 'table'=>'T_slug', 'fk'=>'slug_itm_ID', 'msg'=>T_('%d slugs') ),
 147                  array( 'table'=>'T_items__itemtag', 'fk'=>'itag_itm_ID', 'msg'=>T_('%d links to tags') ),
 148                  array( 'table'=>'T_items__item_settings', 'fk'=>'iset_item_ID', 'msg'=>T_('%d items settings') ),
 149                  array( 'table'=>'T_items__subscriptions', 'fk'=>'isub_item_ID', 'msg'=>T_('%d items subscriptions') ),
 150              );
 151  
 152          $this->objtype = $objtype;
 153  
 154          if( $db_row == NULL )
 155          { // New item:
 156              $this->ID = 0;
 157              $this->set( 'issue_date', date('Y-m-d H:i:s', $localtimenow) );
 158          }
 159          else
 160          {
 161              $this->ID = $db_row->$dbIDname;
 162              $this->issue_date = $db_row->post_datestart;            // Publication date of a post/item
 163              $this->datestart = $db_row->post_datestart;            // This is the same as issue_date, but unfortunatly both of them are used, One of them should be removed
 164              $this->datemodified = $db_row->post_datemodified;            // Date of last edit of post/item
 165              $this->main_cat_ID = $db_row->post_main_cat_ID;
 166              $this->urltitle = $db_row->post_urltitle;
 167              $this->canonical_slug_ID = $db_row->post_canonical_slug_ID;
 168              $this->tiny_slug_ID = $db_row->post_tiny_slug_ID;
 169              $this->title = $db_row->post_title;
 170              $this->excerpt = $db_row->post_excerpt;
 171              $this->ptyp_ID = $db_row->post_ptyp_ID;
 172              $this->url = $db_row->post_url;
 173          }
 174      }
 175  
 176  
 177      /**
 178       * Is this a Special post (Page, Intros, Sidebar, Advertisement)
 179       *
 180       * @return boolean
 181       */
 182  	function is_special()
 183      {
 184          global $posttypes_specialtypes;
 185  
 186          // Check if this post type is between the special post types
 187          return in_array( $this->ptyp_ID, $posttypes_specialtypes );
 188      }
 189  
 190  
 191      /**
 192       * Is this an Intro post
 193       *
 194       * @return boolean
 195       */
 196  	function is_intro()
 197      {
 198          return ($this->ptyp_ID >= 1500 && $this->ptyp_ID <= 1600);
 199      }
 200  
 201  
 202      /**
 203       * Is this a featured post (any intro post will return false even if it's checked as "featured")
 204       *
 205       * @return boolean
 206       */
 207  	function is_featured()
 208      {
 209          return !( empty($this->featured) || $this->is_intro() );
 210      }
 211  
 212  
 213    /**
 214       * Generate a single post link for the item
 215       *
 216       * @param boolean allow redir to permalink, true | false | 'auto' to prevent redit only if single isn't the current permalink type
 217        * @param string base url to use
 218       * @param string glue between url params
 219       */
 220  	function get_single_url( $allow_redir = true, $blogurl = '', $glue = '&amp;' )
 221      {
 222          $this->get_Blog();
 223  
 224          if( empty( $blogurl ) )
 225          {
 226              $blogurl = $this->Blog->gen_blogurl();
 227          }
 228  
 229          $single_links = $this->Blog->get_setting('single_links');
 230  
 231           if( !empty( $this->urltitle ) && $single_links != 'param_num' )
 232          {    // We can and we want to use the url title:
 233              $urlparam = 'title='.$this->urltitle;
 234              $urltail = $this->urltitle;
 235          }
 236          else
 237          {
 238              $urlparam = 'p='.$this->ID;
 239              $urltail = 'p'.$this->ID;
 240          }
 241  
 242          switch( $single_links )
 243          {
 244              case 'param_num':
 245              case 'param_title':
 246                  $permalink = url_add_param( $blogurl, $urlparam.$glue.'more=1'.$glue.'c=1'.$glue.'tb=1'.$glue.'pb=1', $glue );
 247                  break;
 248  
 249              case 'y':
 250                  $permalink = url_add_tail( $blogurl, mysql2date('/Y/', $this->issue_date).$urltail );
 251                  break;
 252  
 253              case 'ym':
 254                  $permalink = url_add_tail( $blogurl, mysql2date('/Y/m/', $this->issue_date).$urltail );
 255                  break;
 256  
 257              case 'ymd':
 258                  $permalink = url_add_tail( $blogurl, mysql2date('/Y/m/d/', $this->issue_date).$urltail );
 259                  break;
 260  
 261              case 'subchap':
 262                  $main_Chapter = & $this->get_main_Chapter();
 263                  $permalink = url_add_tail( $blogurl, '/'.$main_Chapter->urlname.'/'.$urltail );
 264                  break;
 265  
 266              case 'chapters':
 267                  $main_Chapter = & $this->get_main_Chapter();
 268                  $permalink = url_add_tail( $blogurl, '/'.$main_Chapter->get_url_path().$urltail );
 269                  break;
 270  
 271              case 'short':
 272              default:
 273                  $permalink = url_add_tail( $blogurl, '/'.$urltail );
 274                  break;
 275          }
 276  
 277          if( $allow_redir == 'auto' )
 278          {    // We allow redir only if the permalink is already single.
 279              // In other words: we implicitely allow redir if there is no need to redir!
 280              // and more useful: we explicitly prevent redir if we know it would take place.
 281              $allow_redir = ($this->Blog->get_setting( 'permalinks' ) == 'single');
 282          }
 283  
 284          if( ! $allow_redir )
 285          {
 286              $permalink = url_add_param( $permalink, 'redir=no', $glue );
 287          }
 288  
 289          return $permalink;
 290      }
 291  
 292  
 293      /**
 294       * Generate a link to the post in the archives
 295       *
 296        * @param string base url to use
 297       * @param string glue between url params
 298       */
 299  	function get_archive_url( $blogurl = '', $glue = '&amp;' )
 300      {
 301          $this->get_Blog();
 302  
 303          if( empty( $blogurl ) )
 304          {
 305              $blogurl = $this->Blog->gen_blogurl();
 306          }
 307  
 308          $permalink = $this->Blog->get_archive_url( $this->issue_date, $glue );
 309  
 310          return $permalink.'#item_'.$this->ID;
 311      }
 312  
 313  
 314      /**
 315       * Generate a link to the post in the category
 316       *
 317        * @param string base url to use
 318       * @param string glue between url params
 319       */
 320  	function get_chapter_url( $blogurl = '', /* TODO: not used.. */ $glue = '&amp;' )
 321      {
 322          if( empty( $blogurl ) )
 323          {
 324              $this->get_Blog();
 325              $blogurl = $this->Blog->gen_blogurl();
 326          }
 327  
 328          $main_Chapter = & $this->get_main_Chapter();
 329          $permalink = url_add_tail( $blogurl, '/'.$main_Chapter->get_url_path() );
 330  
 331          return $permalink.'#item_'.$this->ID;
 332      }
 333  
 334  
 335      /**
 336       * Generate the permalink for the item.
 337       *
 338       * Note: Each item has an unique permalink at any given time.
 339       * Some admin settings may however change the permalinks for previous items.
 340       * Note: This actually only returns the URL, to get a real link, use {@link Item::get_permanent_link()}
 341       *
 342       * @todo archives modes in clean URL mode
 343       *
 344       * @param string single, archive, subchap
 345       * @param string base url to use
 346       * @param string glue between url params
 347       */
 348  	function get_permanent_url( $permalink_type = '', $blogurl = '', $glue = '&amp;' )
 349      {
 350          global $DB, $cacheweekly, $Settings, $posttypes_specialtypes, $posttypes_nopermanentURL, $posttypes_catpermanentURL;
 351  
 352          if( in_array( $this->ptyp_ID, $posttypes_specialtypes ) ) // page, intros, sidebar
 353          {    // This is not an "in stream" post:
 354              if( in_array( $this->ptyp_ID, $posttypes_nopermanentURL ) )
 355              {    // This type of post is not allowed to have a permalink:
 356                  $permalink_type = 'none';
 357              }
 358              if( in_array( $this->ptyp_ID, $posttypes_catpermanentURL ) )
 359              {    // This post has a permanent URL as url to main chapter:
 360                  $permalink_type = 'cat';
 361              }
 362              else
 363              { // allowed to have a permalink:
 364                  // force use of single url:
 365                  $permalink_type = 'single';
 366              }
 367          }
 368          elseif( empty( $permalink_type ) )
 369          {    // Normal "in stream" post:
 370              // Use default from collection settings (may be an "in stream" URL):
 371              $this->get_Blog();
 372              $permalink_type = $this->Blog->get_setting( 'permalinks' );
 373          }
 374  
 375          switch( $permalink_type )
 376          {
 377              case 'archive':
 378                  return $this->get_archive_url( $blogurl, $glue );
 379  
 380              case 'subchap':
 381                  return $this->get_chapter_url( $blogurl, $glue );
 382  
 383              case 'none':
 384                  // This is a silent fallback when we try to permalink to an Item that cannot be addressed directly:
 385                  // Link to blog home:
 386                  $this->get_Blog();
 387                  return $this->Blog->gen_blogurl();
 388  
 389              case 'cat':
 390                  // Link to permanent url of main chapter:
 391                  $this->get_main_Chapter();
 392                  return $this->main_Chapter->get_permanent_url( NULL, $blogurl, 1, NULL, $glue );
 393  
 394              case 'single':
 395              default:
 396                  return $this->get_single_url( true, $blogurl, $glue );
 397          }
 398      }
 399  
 400  
 401      /**
 402       * Template function: list all the category names
 403       *
 404       * @param string Output format for each cat, see {@link format_to_output()}
 405       */
 406  	function categories( $params = array() )
 407      {
 408          // Make sure we are not missing any param:
 409          $params = array_merge( array(
 410                  'before'          => ' ',
 411                  'after'           => ' ',
 412                  'include_main'    => true,
 413                  'include_other'   => true,
 414                  'include_external'=> true,
 415                  'before_main'     => '',       // string fo display before the MAIN category,
 416                  'after_main'      => '',       // string fo display after the MAIN category
 417                  'before_other'    => '',       // string fo display before OTHER categories
 418                  'after_other'     => '',       // string fo display after OTHER categories
 419                  'before_external' => '<em>',   // string fo display before EXTERNAL categories
 420                  'after_external'  => '</em>',  // string fo display after EXTERNAL categories,
 421                  'separator'       => ', ',
 422                  'link_categories' => true,
 423                  'link_title'      => '#',
 424                  'format'          => 'htmlbody',
 425                  'show_locked'     => false,
 426              ), $params );
 427  
 428  
 429          if( $params['link_title'] == '#' )
 430          { /* TRANS: When the categories for a specific post are displayed, the user can click
 431                      on these cats to browse them, this is the default href title displayed there */
 432              $params['link_title'] = T_('Browse category');
 433          }
 434  
 435          $categoryNames = array();
 436          foreach( $this->get_Chapters() as $Chapter )
 437          {
 438              $cat_name = $Chapter->dget( 'name' );
 439  
 440              if( $params['link_categories'] )
 441              { // we want to display links
 442                  $lBlog = & $Chapter->get_Blog();
 443                  $cat_name = '<a href="'.$Chapter->get_permanent_url().'" title="'.htmlspecialchars($params['link_title']).'">'.$cat_name.'</a>';
 444              }
 445  
 446              if( $Chapter->ID == $this->main_cat_ID )
 447              { // We are displaying the main cat!
 448                  if( !$params['include_main'] )
 449                  { // ignore main cat !!!
 450                      continue;
 451                  }
 452                  $cat_name = $params['before_main'].$cat_name.$params['after_main'];
 453              }
 454              elseif( $Chapter->blog_ID == $this->blog_ID )
 455              { // We are displaying another cat in the same blog
 456                  if( !$params['include_other'] )
 457                  { // ignore main cat !!!
 458                      continue;
 459                  }
 460                  $cat_name = $params['before_other'].$cat_name.$params['after_other'];
 461              }
 462              else
 463              { // We are displaying an external cat (in another blog)
 464                  if( !$params['include_external'] )
 465                  { // ignore main cat !!!
 466                      continue;
 467                  }
 468                  $cat_name = $params['before_external'].$cat_name.$params['after_external'];
 469              }
 470  
 471              if( $Chapter->lock && $params[ 'show_locked' ] )
 472              {
 473                  $cat_name .= '<span style="padding-left:5px;" >'.get_icon( 'file_not_allowed', 'imgtag', array( 'title' => T_('Locked')) ).'</span>';
 474              }
 475  
 476              $categoryNames[] = $cat_name;
 477          }
 478  
 479          echo $params['before'];
 480          echo format_to_output( implode( $params['separator'], $categoryNames ), $params['format'] );
 481           echo $params['after'];
 482      }
 483  
 484  
 485      /**
 486       * Add nav_target param into the end of the url, but only if it is necessary
 487       *
 488       * @param string the url
 489       * @param string the current blog or current skin post_navigation setting
 490       * @param integer the ID of the navigation target
 491       * @param string glue
 492       * @return string the received url or the received url extended with the navigation param
 493       */
 494  	function add_navigation_param( $url, $post_navigation, $nav_target, $glue = '&amp;' )
 495      {
 496          if( empty( $url ) || empty( $nav_target ) )
 497          { // the url or the navigation target is not set we can't modify anything
 498              return $url;
 499          }
 500  
 501          switch( $post_navigation )
 502          {
 503              case 'same_category': // navigate through the selected category
 504                  if( $this->main_cat_ID != $nav_target )
 505                  {
 506                      $url = url_add_param( $url, 'cat='.$nav_target, $glue );
 507                  }
 508                  break;
 509  
 510              // 'same_tag' should be added here, with 'tag' param
 511  
 512              case 'same_author': // navigate through this item author's posts ( param not needed because a post always has only one author )
 513              case 'same_blog': // by default don't add any param
 514              default:
 515                  break;
 516          }
 517  
 518          return $url;
 519      }
 520  
 521  
 522      /**
 523       * Template function: display main category name
 524       *
 525       * @param string Output format, see {@link format_to_output()}
 526       * @param array Params
 527       */
 528  	function main_category( $format = 'htmlbody', $params = array() )
 529      {
 530          $params = array_merge( array(
 531                  'display_link' => false, // TRUE to display category's name as link
 532                  'link_class'   => ''
 533              ), $params );
 534  
 535          $Chapter = & $this->get_main_Chapter();
 536  
 537          if( $params['display_link'] )
 538          {    // Display category's name as link
 539  
 540              $link_class = '';
 541              if( !empty( $params['link_class'] ) )
 542              {    // Set attribute for class
 543                  $link_class = 'class="'.$params['link_class'].'"';
 544              }
 545  
 546              echo '<a href="'.$Chapter->get_permanent_url().'"'.$link_class.'>';
 547          }
 548  
 549          // Display category's name
 550          $Chapter->disp( 'name', $format );
 551  
 552          if( $params['display_link'] )
 553          {
 554              echo '</a>';
 555          }
 556      }
 557  
 558  
 559      /**
 560       * Get list of Chapter objects.
 561       *
 562       * sam2kb> TODO: Cache item cat IDs into Item::categories property instead of global $cache_postcats
 563       *
 564       * @return array of {@link Chapter chapters} (references)
 565       */
 566  	function get_Chapters()
 567      {
 568          global $DB, $preview, $postIDlist, $cache_postcats;
 569  
 570          if( $preview )
 571          {    // Preview mode
 572              global $extracats, $post_category;
 573  
 574              $extracats = param( 'post_extracats', 'array/integer', array() );
 575              if( ( ! empty( $post_category ) ) && ( ! in_array( $post_category, $extracats ) ) )
 576              {
 577                  $extracats[] = $post_category;
 578              }
 579              $categoryIDs = $extracats;
 580          }
 581          elseif( empty( $this->ID ) )
 582          { // This item doesn't exist yet
 583              $categoryIDs = NULL;
 584          }
 585          else
 586          {
 587              $search_post_ids = empty( $postIDlist ) ? NULL : explode( ',', $postIDlist );
 588              if( empty( $search_post_ids ) || !in_array( $this->ID, $search_post_ids ) )
 589              {    // Load cats for current item
 590                  $categoryIDs = postcats_get_byID( $this->ID );
 591              }
 592              else
 593              {    // Load cats for items list
 594                  if( ! isset($cache_postcats[$this->ID]) )
 595                  {    // Add to cache
 596                      $sql = "SELECT postcat_post_ID, postcat_cat_ID
 597                              FROM T_postcats
 598                              WHERE postcat_post_ID IN ($postIDlist)
 599                              ORDER BY postcat_post_ID, postcat_cat_ID";
 600  
 601                      foreach( $DB->get_results( $sql, ARRAY_A, 'Get categories for items' ) as $row )
 602                      {
 603                          $postcat_post_ID = $row['postcat_post_ID'];
 604                          if( ! isset( $cache_postcats[$postcat_post_ID] ) )
 605                          {
 606                               $cache_postcats[$postcat_post_ID] = array();
 607                          }
 608                          $cache_postcats[$postcat_post_ID][] = $row['postcat_cat_ID'];
 609                      }
 610                  }
 611                  $categoryIDs = $cache_postcats[$this->ID];
 612              }
 613          }
 614  
 615          $chapters = array();
 616          if( ! empty( $categoryIDs ) )
 617          {
 618              $ChapterCache = & get_ChapterCache();
 619              // Load all required Chapters
 620              $ChapterCache->load_list( $categoryIDs );
 621  
 622              foreach( $categoryIDs as $cat_ID )
 623              {
 624                  if( $Chapter = & $ChapterCache->get_by_ID( $cat_ID, false ) )
 625                  {
 626                      $chapters[] = $Chapter;
 627                  }
 628              }
 629          }
 630  
 631          return $chapters;
 632      }
 633  
 634  
 635      /**
 636       * Get the main Chapter.
 637       *
 638       * @return Chapter
 639       */
 640      function & get_main_Chapter()
 641      {
 642          if( is_null( $this->main_Chapter ) )
 643          {
 644              $ChapterCache = & get_ChapterCache();
 645              /**
 646               * @var Chapter
 647               */
 648              $this->main_Chapter = & $ChapterCache->get_by_ID( $this->main_cat_ID, false );
 649              if( empty( $this->main_Chapter ) )
 650              {    // If main chapter is broken we should get it from one of extra chapters
 651                  $chapters = $this->get_Chapters();
 652                  foreach( $chapters as $Chapter )
 653                  {
 654                      if( !empty( $Chapter ) )
 655                      {    // We have found a valid Chapter...
 656                          $this->main_Chapter = & $Chapter;
 657                          $this->main_cat_ID = $Chapter->ID;
 658                          break;
 659                      }
 660                  }
 661              }
 662              if( empty( $this->main_Chapter ) )
 663              {    // If we still don't have a valid Chapter, display clean error and die().
 664                  global $admin_url, $Blog, $blog;
 665                  if( empty( $Blog ) )
 666                  {
 667                      if( !empty( $blog ) )
 668                      {
 669                          $BlogCache = & get_BlogCache();
 670                          $Blog = & $BlogCache->get_by_ID( $blog, false );
 671                      }
 672                  }
 673  
 674                  $url_to_edit_post = $admin_url.'?ctrl=items&amp;action=edit&amp;p='.$this->ID;
 675  
 676                  if( !empty( $Blog ) )
 677                  {
 678                      $url_to_edit_post .= '&amp;blog='.$Blog->ID;
 679                      if( is_admin_page() )
 680                      {    // Try to set a main category
 681                          $default_cat_ID = $Blog->get_setting( 'default_cat_ID' );
 682                          if( !empty( $default_cat_ID ) )
 683                          {    // If default category is set
 684                              $this->main_cat_ID = $default_cat_ID;
 685                              $this->main_Chapter = & $ChapterCache->get_by_ID( $this->main_cat_ID, false );
 686                          }
 687                          else
 688                          {    // Set from first chapter of the blog
 689                              $ChapterCache->clear();
 690                              $ChapterCache->load_subset( $Blog->ID );
 691                              if( $Chapter = & $ChapterCache->get_next() )
 692                              {
 693                                  $this->main_cat_ID = $Chapter->ID;
 694                                  $this->main_Chapter = & $Chapter;
 695                              }
 696                          }
 697                      }
 698                  }
 699  
 700                  $message = sprintf( 'Item with ID <a %s>%s</a> has an invalid main category ID %s.',
 701                          'href="'.$url_to_edit_post.'"',
 702                          $this->ID,
 703                          $this->main_cat_ID
 704                      );
 705                  if( empty( $Blog ) )
 706                  {    // No blog defined
 707                      $message .= ' In addition we cannot fallback to the default category because no valid blog ID has been specified.';
 708                  }
 709  
 710                  if( empty( $this->main_Chapter ) )
 711                  {    // Main chapter is not defined, because blog doesn't have the default cat ID and even blog doesn't have any categories
 712                      debug_die( $message );
 713                  }
 714                  else
 715                  {    // Main chapter is defined, we can show the page
 716                      global $Messages;
 717                      $Messages->add( $message );
 718                  }
 719              }
 720          }
 721  
 722          return $this->main_Chapter;
 723      }
 724  
 725  
 726      /**
 727       * Get the blog ID of this item (derived from main chapter).
 728       * @return integer
 729       */
 730  	function get_blog_ID()
 731      {
 732          if( is_null($this->blog_ID) )
 733          {
 734              $main_Chapter = & $this->get_main_Chapter();
 735              $this->blog_ID = $main_Chapter->blog_ID;
 736          }
 737          return $this->blog_ID;
 738      }
 739  
 740  
 741      /**
 742       * returns issue date (datetime) of Item
 743       * @param array
 744       *   - 'before'
 745       *   - 'after'
 746       *   - 'date_format': Date format
 747       *   - 'use_GMT': Use GMT/UTC date
 748       */
 749  	function get_issue_date( $params = array() )
 750      {
 751          // Make sure we are not missing any param:
 752          $params = array_merge( array(
 753                  'before'      => ' ',
 754                  'after'       => ' ',
 755                  'date_format' => '#',
 756                  'use_GMT'     => false,
 757              ), $params );
 758  
 759          if( $params['date_format'] == '#' )
 760          {
 761              $params['date_format'] = locale_datefmt();
 762          }
 763  
 764          return $params['before'].mysql2date( $params['date_format'], $this->issue_date, $params['use_GMT'] ).$params['after'];
 765      }
 766  
 767  
 768      /**
 769       * Template function: display issue date (datetime) of Item
 770       * @see get_issue_date()
 771       */
 772  	function issue_date( $params = array() )
 773      {
 774          echo $this->get_issue_date( $params );
 775      }
 776  
 777  
 778      /**
 779       * Template function: display issue time (datetime) of Item
 780       * @param array
 781       *   - 'time_format': Time format
 782       *   - ... see {@link get_issue_date()}
 783       * @see get_issue_date()
 784       */
 785  	function issue_time( $params = array() )
 786      {
 787          // Make sure we are not missing any param:
 788          $params = array_merge( array(
 789                  'time_format' => '#',
 790              ), $params );
 791  
 792          if( !isset($params['date_format']) )
 793          {
 794              $params['date_format'] = $params['time_format'];
 795          }
 796  
 797          if( $params['date_format'] == '#' )
 798          {
 799              $params['date_format'] = locale_timefmt();
 800          }
 801  
 802          echo $this->get_issue_date( $params );
 803      }
 804  
 805  
 806      /**
 807       * Template function: display locale for item
 808       */
 809  	function lang()
 810      {
 811          $this->disp( 'locale', 'raw' );
 812      }
 813  
 814  
 815      /**
 816       * Template function: display locale for item
 817       */
 818  	function locale()
 819      {
 820          $this->disp( 'locale', 'raw' );
 821      }
 822  
 823  
 824      /**
 825       * Template tag
 826       */
 827  	function locale_flag( $params = array() )
 828      {
 829          // Make sure we are not missing any param:
 830          $params = array_merge( array(
 831                  'before'      => ' ',
 832                  'after'       => ' ',
 833                  'collection'  => 'h10px',
 834                  'format'      => 'htmlbody',
 835                  'class'       => 'flag',
 836                  'align'       => '',
 837                  'locale'      => 'item', // Possible values: 'item', 'blog', custom locale, empty string for current locale
 838              ), $params );
 839  
 840          if( $params['locale'] == 'blog' )
 841          {
 842              $params['locale'] = $this->get_Blog()->locale;
 843          }
 844          elseif( $params['locale'] == 'item' )
 845          {
 846              $params['locale'] = $this->locale;
 847          }
 848  
 849          echo $params['before'];
 850          echo locale_flag( $params['locale'], $params['collection'], $params['class'], $params['align'] );
 851          echo $params['after'];
 852      }
 853  
 854  
 855      /**
 856       * Template function: Temporarily switch to this post's locale
 857       */
 858  	function locale_temp_switch()
 859      {
 860          locale_temp_switch( $this->locale );
 861      }
 862  
 863  
 864      /**
 865       * Template function: display language name for item
 866       *
 867       * @param string Output format, see {@link format_to_output()}
 868       */
 869  	function language( $format = 'htmlbody' )
 870      {
 871          global $locales;
 872          $locale = $locales[ $this->locale ];
 873          echo format_to_output( $locale['name'], $format );
 874      }
 875  
 876      /**
 877       * Get last mod date (datetime) of Item
 878       *
 879       * @param string date/time format: leave empty to use locale default date format
 880       * @param boolean true if you want GMT
 881       */
 882  	function get_mod_date( $format = '', $useGM = false )
 883      {
 884          if( empty($format) )
 885          {
 886              return mysql2date( locale_datefmt(), $this->datemodified, $useGM );
 887          }
 888  
 889          return mysql2date( $format, $this->datemodified, $useGM );
 890      }
 891  
 892  
 893      /**
 894       * Template function: display last mod date (datetime) of Item
 895       *
 896       * @param string date/time format: leave empty to use locale default date format
 897       * @param boolean true if you want GMT
 898       */
 899  	function mod_date( $format = '', $useGM = false )
 900      {
 901          echo $this->get_mod_date( $format, $useGM );
 902      }
 903  
 904  
 905      /**
 906       * Template function: display last mod time (datetime) of Item
 907       *
 908       * @param string date/time format: leave empty to use locale default time format
 909       * @param boolean true if you want GMT
 910       */
 911  	function mod_time( $format = '', $useGM = false )
 912      {
 913          if( empty($format) )
 914              echo mysql2date( locale_timefmt(), $this->datemodified, $useGM );
 915          else
 916              echo mysql2date( $format, $this->datemodified, $useGM );
 917      }
 918  
 919  
 920      /**
 921       * Check if current item has at least one category, which belongs to the given blog
 922       *
 923       * @param integer the given blog ID
 924       * @return boolean true if there is at least one category in the given blog, false otherwise
 925       */
 926  	function is_part_of_blog( $blog_ID )
 927      {
 928          global $DB;
 929          $cat_count = $DB->get_var( '
 930                  SELECT count( cat_ID )
 931                  FROM T_categories, T_postcats
 932                  WHERE
 933                      T_categories.cat_ID = T_postcats.postcat_cat_ID
 934                      and T_categories.cat_blog_ID = '.$blog_ID.'
 935                      and T_postcats.postcat_post_ID = '.$this->ID
 936          );
 937  
 938          // $cat_count>0 means that this item has at least one category that belongs to the target blog.
 939          return $cat_count > 0;
 940      }
 941  
 942  
 943      /**
 944       * Check if cross post navigation should stay in the current blog or not.
 945       * Also check that this item has at least one category that belongs to the given blog.
 946       * If current blog is the same as item blog then, this function will return false, because no need to check.
 947       *
 948       * @param string 'auto' value means this call needs to decide to stay in the current blog or not. Every other value will return false!
 949       * @param integer the given "current" blog ID (its usually the current blog id)
 950       * @return boolean true if we have to stay in the current blog, false otherwise
 951       */
 952  	function check_cross_post_nav( $target_blog, $blog_ID )
 953      {
 954          global $cross_post_nav_in_same_blog;
 955  
 956          if( $target_blog != 'auto' )
 957          { // target_blog is not set to auto, we have to navigate to the item's main cat's blog.
 958              return false;
 959          }
 960  
 961          $this->get_Blog();
 962          if( $this->Blog->ID == $blog_ID )
 963          { // item's blog is the same as target blog
 964              return false;
 965          }
 966  
 967          if( ! $cross_post_nav_in_same_blog )
 968          { // we have to navigate to the item's main cat's blog.
 969              return false;
 970          }
 971  
 972          // return true if current item has at least one category, which belongs to the corresponding blog, false otherwise
 973          return $this->is_part_of_blog( $blog_ID );
 974      }
 975  
 976  
 977      /**
 978       * Template function: display permalink for item
 979       *
 980       * Note: This actually only outputs the URL, to display a real link, use {@link Item::permanent_link()}
 981       *
 982       * @param string 'post', 'archive#id' or 'archive#title'
 983       * @param string url to use
 984       */
 985  	function permanent_url( $mode = '', $blogurl='' )
 986      {
 987          echo $this->get_permanent_url( $mode, $blogurl );
 988      }
 989  
 990  
 991      /**
 992       * Returns a permalink link to the Item
 993       *
 994       * Note: If you only want the permalink URL, use {@link Item::get_permanent_url()}
 995       *
 996       * @param string link text or special value: '#', '#icon#', '#text#', '#title#' '... $title$ ...'
 997       * @param string link title
 998       * @param string class name
 999       */
1000  	function get_permanent_link( $text = '#', $title = '#', $class = '', $target_blog = '', $post_navigation = '', $nav_target = NULL )
1001      {
1002          global $current_User, $Blog;
1003  
1004          switch( $text )
1005          {
1006              case '#':
1007                  $text = get_icon( 'permalink', 'imgtag', array('class'=>'icon') ).T_('Permalink');
1008                  break;
1009  
1010              case '#icon#':
1011                  $text = get_icon( 'permalink', 'imgtag', array('class'=>'icon') );
1012                  break;
1013  
1014              case '#text#':
1015                  $text = T_('Permalink');
1016                  break;
1017  
1018              case '#title#':
1019                  $text = format_to_output( $this->title );
1020                  break;
1021          }
1022  
1023          if( $title == '#' ) $title = T_('Permanent link to full entry');
1024  
1025          $blogurl = '';
1026          $permalink_type = '';
1027          if( !empty($Blog) && $this->check_cross_post_nav( $target_blog, $Blog->ID ) )
1028          {
1029              $permalink_type = $Blog->get_setting( 'permalinks' );
1030              $blogurl = $Blog->gen_blogurl();
1031          }
1032  
1033          $url = $this->get_permanent_url( $permalink_type, $blogurl );
1034          // add navigation param if necessary
1035          $url = $this->add_navigation_param( $url, $post_navigation, $nav_target );
1036  
1037          // Display as link
1038          $r = '<a href="'.$url.'" title="'.$title.'"';
1039          if( !empty( $class ) ) $r .= ' class="'.$class.'"';
1040          $r .= '>'.str_replace( '$title$', format_to_output( $this->title ), $text ).'</a>';
1041  
1042          return $r;
1043      }
1044  
1045  
1046      /**
1047       * Displays a permalink link to the Item
1048       *
1049       * Note: If you only want the permalink URL, use {@link Item::permanent_url()}
1050       *
1051       * @param string link text or special value:
1052       * @param string link title
1053       * @param string class name
1054       */
1055  	function permanent_link( $params = array() )
1056      {
1057          // Make sure we are not missing any param:
1058          $params = array_merge( array(
1059                  'before'      => '',
1060                  'after'       => '',
1061                  'text'        => '#',    // possible special values: '#', '#icon#', '#text#', '#title#'
1062                  'title'       => '#',
1063                  'class'       => '',
1064                  'target_blog' => '',
1065              //    'format'      => 'htmlbody',
1066              ), $params );
1067  
1068          $link = $this->get_permanent_link( $params['text'], $params['title'], $params['class'], $params['target_blog'] );
1069  
1070          if( !empty( $link ) )
1071          {
1072              echo $params['before'];
1073              echo $link;
1074              echo $params['after'];
1075          }
1076      }
1077  
1078  
1079      /**
1080       * Template function: display title for item and link to related URL
1081       */
1082  	function title( $params = array() )
1083      {
1084          $params = array_merge( array(
1085                  'target_blog'  => 'auto',
1086              ), $params );
1087          echo $this->get_title($params);
1088      }
1089  
1090  
1091      /**
1092       * Get "nice" title of the Item
1093       * @return string
1094       */
1095  	function get_title( $params = array() )
1096      {
1097          global $ReqURL, $Blog, $MainList;
1098  
1099          // Set default post navigation
1100          $def_post_navigation = empty( $Blog ) ? 'same_blog' : $Blog->get_setting( 'post_navigation' );
1101  
1102          // Make sure we are not missing any param:
1103          $params = array_merge( array(
1104                  'before'          => '',
1105                  'after'           => '',
1106                  'format'          => 'htmlbody',
1107                  'link_type'       => '#',
1108                  'link_class'      => '#',
1109                  'max_length'      => '',
1110                  'target_blog'     => '',
1111                  'nav_target'      => NULL,
1112                  'post_navigation' => $def_post_navigation,
1113                  'title_field'     => 'title',
1114              ), $params );
1115  
1116          // Set post navigation target
1117          $nav_target = ( ( $params['nav_target'] === NULL ) && isset($MainList) && !empty( $MainList->nav_target ) ) ? $MainList->nav_target : $params['nav_target'];
1118  
1119          $blogurl = '';
1120          if( !empty($Blog) && $this->check_cross_post_nav( $params['target_blog'], $Blog->ID ) )
1121          {
1122              $blogurl = $Blog->gen_blogurl();
1123          }
1124  
1125          $title = format_to_output( $this->$params['title_field'], $params['format'] );
1126  
1127          if( $params['max_length'] != '' )
1128          {    // Crop long title
1129              $title = strmaxlen( $title, intval($params['max_length']) );
1130          }
1131  
1132          if( empty( $title ) )
1133          {
1134              return;
1135          }
1136  
1137          if( $params['link_type'] == '#' )
1138          {    // Use default link type from settings:
1139              if( $this->is_intro() )
1140              {    // This is an intro, do not link title by default:
1141                  $params['link_type'] = 'none';
1142              }
1143              elseif( is_same_url( $this->get_permanent_url( '', $blogurl, '&' ), $ReqURL ) )
1144              {    // We are on the single url already:
1145                  $params['link_type'] = 'none';
1146              }
1147              else if( $this->ptyp_ID == 3000 )
1148              {    // tblue> This is a sidebar link, link to its "link to" URL by default:
1149                  $params['link_type'] = 'linkto_url';
1150              }
1151              else
1152              {    // This is a normal post: use default link strategy from Blog settings:
1153                  $this->get_Blog();
1154                  $params['link_type'] = $this->Blog->get_setting( 'title_link_type' );
1155              }
1156          }
1157  
1158          switch( $params['link_type'] )
1159          {
1160              case 'auto':
1161                  $url = ( empty($this->url) ? $this->get_permanent_url() : $this->url );
1162                  break;
1163  
1164              case 'permalink':
1165                  $url = $this->get_permanent_url( '', $blogurl );
1166                  break;
1167  
1168              case 'linkto_url':
1169                  $url = $this->url;
1170                  break;
1171  
1172              case 'admin_view':
1173                  $url = '?ctrl=items&amp;blog='.$this->get_blog_ID().'&amp;p='.$this->ID;
1174                  break;
1175  
1176              case 'none':
1177              default:
1178          }
1179  
1180          if( !empty( $url ) )
1181          { // url is set, also add navigation param if it is necessary
1182              $url = $this->add_navigation_param( $url, $params['post_navigation'], $nav_target );
1183          }
1184  
1185          $link_class = '';
1186          if( $params['link_class'] != '#' )
1187          {
1188              $link_class = ' class="'.$params['link_class'].'"';
1189          }
1190  
1191          $r = $params['before'];
1192          if( !empty($url) )
1193          {
1194              $r .= '<a href="'.$url.'"'.$link_class.'>'.$title.'</a>';
1195          }
1196          else
1197          {
1198              $r .= $title;
1199          }
1200          $r .= $params['after'];
1201          return $r;
1202      }
1203  
1204  
1205      /**
1206       * Template function: display type of item
1207       *
1208       * @param string
1209       * @param string
1210       * @param string Output format, see {@link format_to_output()}
1211       */
1212  	function type( $before = '', $after = '', $format = 'htmlbody' )
1213      {
1214          $ItemTypeCache = & get_ItemTypeCache();
1215          $Element = & $ItemTypeCache->get_by_ID( $this->ptyp_ID, true, false );
1216          if( !$Element )
1217          { // No status:
1218              return;
1219          }
1220  
1221          $type_name = $Element->get('name');
1222  
1223          if( $format == 'raw' )
1224          {
1225              $this->disp( $type_name, 'raw' );
1226          }
1227          else
1228          {
1229              echo $before.format_to_output( $type_name, $format ).$after;
1230          }
1231      }
1232  
1233  
1234      /**
1235       * Template function: get excerpt
1236       *
1237       * @todo do we want excerpts in itemLight or not?
1238       *       dh> I'd say "no". I have added excerpt_autogenerated
1239       *           only to Item now. But makes sense in the same class.
1240       *           update_excerpt is also on in Item.
1241       *  fp> the issue is about display only. of course we don't want update code in ItemLight.
1242       *  The question is typically about being able to display excerpts in ItemLight list
1243       *  sitemaps, feed, recent posts, post widgets where the exceprt might be used as a title, etc.
1244       *
1245       * @param string filename to use to display more
1246       * @return string
1247       */
1248  	function get_excerpt( $format = 'htmlbody' )
1249      {
1250          // Character conversions
1251          return format_to_output( $this->excerpt, $format );
1252      }
1253  
1254  
1255      /**
1256       * Set param value
1257       *
1258       * By default, all values will be considered strings
1259       *
1260       * @todo extra_cat_IDs recording
1261       *
1262       * @param string parameter name
1263       * @param mixed parameter value
1264       * @param boolean true to set to NULL if empty value
1265       * @return boolean true, if a value has been set; false if it has not changed
1266       */
1267  	function set( $parname, $parvalue, $make_null = false )
1268      {
1269          switch( $parname )
1270          {
1271              case 'main_cat_ID':
1272                  $r = $this->set_param( 'main_cat_ID', 'number', $parvalue, false );
1273                  // make sure main cat is in extracat list and there are no duplicates
1274                  $this->extra_cat_IDs[] = $this->main_cat_ID;
1275                  $this->extra_cat_IDs = array_unique( $this->extra_cat_IDs );
1276                  // Invalidate derived property:
1277                  $this->blog_ID = NULL;
1278                  unset($this->main_Chapter); // dereference
1279                  $this->main_Chapter = NULL;
1280                  unset($this->Blog);
1281                  $this->Blog = NULL;
1282                  return $r;
1283  
1284              case 'extra_cat_IDs':
1285                  // ARRAY! We do not record this change (yet)
1286                  $this->extra_cat_IDs = $parvalue;
1287                  // make sure main cat is in extracat list and there are no duplicates
1288                  $this->extra_cat_IDs[] = $this->main_cat_ID;
1289                  $this->extra_cat_IDs = array_unique( $this->extra_cat_IDs );
1290                  break;
1291  
1292              case 'issue_date':
1293              case 'datestart':
1294                  // Remove seconds from issue date and start date
1295                  // fp> TODO: this should only be done if the date is in the future. If it's in the past there are no sideeffects to having seconds.
1296                  // asimo> Why do we have two parameter with the same content if only one is stored in the database?
1297                  // Also it doesn't make sense to remove seconds from a db date field because the database format has seconds anyway.
1298                  // If we remove seconds from datstart field, then datestart will be always inserted into the dbchagnes even if it was not changed.
1299                  // If we don't want seconds in the end of the datestart then we need to remove it in the itemlight constructor as well.
1300                  // asimo> We have to set seconds to '00' and not remove them, this way the posts can appear right after creating, and the format is OK as well.
1301                  $parvalue_empty_seconds = remove_seconds(strtotime($parvalue), 'Y-m-d H:i:s');
1302                  $this->issue_date = $parvalue_empty_seconds;
1303                  return $this->set_param( 'datestart', 'date', $parvalue_empty_seconds, false );
1304  
1305              case 'ptyp_ID':
1306              case 'canonical_slug_ID':
1307              case 'tiny_slug_ID':
1308              case 'dateset':
1309              case 'excerpt_autogenerated':
1310                  return $this->set_param( $parname, 'number', $parvalue, true );
1311  
1312              default:
1313                  return $this->set_param( $parname, 'string', $parvalue, $make_null );
1314          }
1315      }
1316  
1317  
1318      /**
1319       * Get the Blog object for the Item.
1320       *
1321       * @return Blog
1322       */
1323      function & get_Blog()
1324      {
1325          if( is_null($this->Blog) )
1326          {
1327              $this->load_Blog();
1328          }
1329  
1330          return $this->Blog;
1331      }
1332  
1333  
1334      /**
1335       * Load the Blog object for the Item, without returning it.
1336       *
1337       * This is needed for {@link Results} object callbacks.
1338       */
1339  	function load_Blog()
1340      {
1341          if( is_null($this->Blog) )
1342          {
1343              $BlogCache = & get_BlogCache();
1344              $this->Blog = & $BlogCache->get_by_ID( $this->get_blog_ID() );
1345          }
1346      }
1347  
1348  }
1349  
1350  ?>

title

Description

title

Description

title

Description

title

title

Body