b2evolution PHP Cross Reference Blogging Systems

Source: /inc/widgets/model/_widget.class.php - 767 lines - 20033 bytes - Summary - Text - Print

Description: This file implements the Widget 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 Widget 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   *
  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://evocms.cvs.sourceforge.net/)
  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   * @package evocore
  20   *
  21   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  22   * @author fplanque: Francois PLANQUE.
  23   *
  24   * @version $Id: _widget.class.php 6136 2014-03-08 07:59:48Z manuel $
  25   */
  26  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  27  
  28  load_class( '_core/model/dataobjects/_dataobject.class.php', 'DataObject' );
  29  
  30  /**
  31   * ComponentWidget Class
  32   *
  33   * A ComponentWidget is a displayable entity that can be placed into a Container on a web page.
  34   *
  35   * @package evocore
  36   */
  37  class ComponentWidget extends DataObject
  38  {
  39      var $coll_ID;
  40      /**
  41       * Container name
  42       */
  43      var $sco_name;
  44      var $order;
  45      /**
  46       * @var string Type of the plugin ("core" or "plugin")
  47       */
  48      var $type;
  49      var $code;
  50      var $params;
  51  
  52      /**
  53       * Indicates whether the widget is enabled.
  54       *
  55       * @var boolean
  56       */
  57      var $enabled;
  58  
  59      /**
  60       * Array of params which have been customized for this widget instance
  61       *
  62       * This is saved to the DB as a serialized string ($params)
  63       */
  64      var $param_array = NULL;
  65  
  66      /**
  67       * Array of params used during display()
  68       */
  69      var $disp_params = NULL;
  70  
  71      /**
  72       * Lazy instantiated.
  73       *
  74       * This gets set/used for widget plugins (those that hook into SkinTag).
  75       * (false if this Widget is not handled by a Plugin)
  76       * @see get_Plugin()
  77       * @var Plugin
  78       */
  79      var $Plugin;
  80  
  81      /**
  82      * @var BlockCache
  83      */
  84      var $BlockCache;
  85  
  86  
  87      /**
  88       * Constructor
  89       *
  90       * @param object data row from db
  91       */
  92  	function ComponentWidget( $db_row = NULL, $type = 'core', $code = NULL )
  93      {
  94          // Call parent constructor:
  95          parent::DataObject( 'T_widget', 'wi_', 'wi_ID' );
  96  
  97          if( is_null($db_row) )
  98          {    // We are creating an object here:
  99              // Using parent:: instead of $this-> in order to fix http://forums.b2evolution.net//viewtopic.php?p=94778
 100              parent::set( 'type', $type );
 101              parent::set( 'code', $code );
 102          }
 103          else
 104          {    // We are loading an object:
 105              $this->ID       = $db_row->wi_ID;
 106              $this->coll_ID  = $db_row->wi_coll_ID;
 107              $this->sco_name = $db_row->wi_sco_name;
 108              $this->type     = $db_row->wi_type;
 109              $this->code     = $db_row->wi_code;
 110              $this->params   = $db_row->wi_params;
 111              $this->order    = $db_row->wi_order;
 112              $this->enabled  = $db_row->wi_enabled;
 113          }
 114      }
 115  
 116  
 117      /**
 118       * Get ref to the Plugin handling this Widget.
 119       *
 120       * @return Plugin
 121       */
 122      function & get_Plugin()
 123      {
 124          global $Plugins;
 125  
 126          if( is_null( $this->Plugin ) )
 127          {
 128              if( $this->type != 'plugin' )
 129              {
 130                  $this->Plugin = false;
 131              }
 132              else
 133              {
 134                  $this->Plugin = & $Plugins->get_by_code( $this->code );
 135              }
 136          }
 137  
 138          return $this->Plugin;
 139      }
 140  
 141  
 142      /**
 143       * Load params
 144       */
 145  	function load_from_Request()
 146      {
 147          load_funcs('plugins/_plugin.funcs.php');
 148  
 149          // Loop through all widget params:
 150          foreach( $this->get_param_definitions( array( 'for_editing' => true, 'for_updating' => true  ) ) as $parname => $parmeta )
 151          {
 152              autoform_set_param_from_request( $parname, $parmeta, $this, 'Widget' );
 153          }
 154      }
 155  
 156  
 157      /**
 158       * Get name of widget
 159       *
 160       * Should be overriden by core widgets
 161       */
 162  	function get_name()
 163      {
 164          if( $this->type == 'plugin' )
 165          {
 166              // Make sure Plugin is loaded:
 167              if( $this->get_Plugin() )
 168              {
 169                  return $this->Plugin->name;
 170              }
 171              return T_('Inactive / Uninstalled plugin');
 172          }
 173  
 174          return T_('Unknown');
 175      }
 176  
 177  
 178      /**
 179       * Get a very short desc. Used in the widget list.
 180       *
 181       * MAY be overriden by core widgets. Example: menu link widget.
 182       */
 183  	function get_short_desc()
 184      {
 185          return $this->get_name();
 186      }
 187  
 188  
 189      /**
 190       * Get a clean description to display in the widget list.
 191       * @return string
 192       */
 193  	function get_desc_for_list()
 194      {
 195          $name = $this->get_name();
 196  
 197          if( $this->type == 'plugin' )
 198          {
 199              return '<strong>'.$name.'</strong> ('.T_('Plugin').')';
 200          }
 201  
 202          $short_desc = $this->get_short_desc();
 203  
 204          if( $name == $short_desc || empty($short_desc) )
 205          {
 206              return '<strong>'.$name.'</strong>';
 207          }
 208  
 209          return '<strong>'.$short_desc.'</strong> ('.$name.')';
 210      }
 211  
 212  
 213      /**
 214       * Get desc of widget
 215       *
 216       * Should be overriden by core widgets
 217       */
 218  	function get_desc()
 219      {
 220          if( $this->type == 'plugin' )
 221          {
 222              // Make sure Plugin is loaded:
 223              if( $this->get_Plugin() )
 224              {
 225                  return $this->Plugin->short_desc;
 226              }
 227              return T_('Inactive / Uninstalled plugin');
 228          }
 229  
 230          return T_('Unknown');
 231      }
 232  
 233  
 234      /**
 235       * Get definitions for editable params.
 236       *
 237       * @see Plugin::GetDefaultSettings()
 238       *
 239       * @param array Local params like 'for_editing' => true
 240       */
 241  	function get_param_definitions( $params )
 242      {
 243  
 244          $r = array();
 245  
 246          if( $this->type == 'plugin' )
 247          {
 248              // Make sure Plugin is loaded:
 249              if( $this->get_Plugin() )
 250              {
 251                  $r = $this->Plugin->get_widget_param_definitions( $params );
 252              }
 253          }
 254  
 255          $r_standart = array(
 256                  'widget_css_class' => array(
 257                      'label' => '<span class="dimmed">'.T_( 'CSS Class' ).'</span>',
 258                      'size' => 20,
 259                      'note' => T_( 'Replaces $wi_class$ in your skins containers.'),
 260                  ),
 261                  'widget_ID' => array(
 262                      'label' => '<span class="dimmed">'.T_( 'DOM ID' ).'</span>',
 263                      'size' => 20,
 264                      'note' => T_( 'Replaces $wi_ID$ in your skins containers.'),
 265                  ),
 266                  'allow_blockcache' => array(
 267                      'label' => T_( 'Allow caching' ),
 268                      'note' => T_( 'Uncheck to prevent this widget from ever being cached in the block cache. (The whole page may still be cached.) This is only needed when a widget is poorly handling caching and cache keys.' ),
 269                      'type' => 'checkbox',
 270                      'defaultvalue' => true,
 271                  ),
 272              );
 273  
 274          return array_merge($r,$r_standart);;
 275      }
 276  
 277  
 278      /**
 279       * Load param array.
 280       */
 281  	function load_param_array()
 282      {
 283          if( is_null( $this->param_array ) )
 284          {    // Param array has not been loaded yet
 285              $this->param_array = @unserialize( $this->params );
 286  
 287              if( empty( $this->param_array ) )
 288              {    // No saved param values were found:
 289                  $this->param_array = array();
 290              }
 291          }
 292      }
 293  
 294  
 295      /**
 296        * Get param value.
 297        * @param string
 298        * @param boolean default false, set to true only if it is called from a widget::get_param_definition() function to avoid infinite loop
 299        * @return mixed
 300       */
 301  	function get_param( $parname, $check_infinite_loop = false )
 302      {
 303          $this->load_param_array();
 304          if( isset( $this->param_array[$parname] ) )
 305          {    // We have a value for this param:
 306              return $this->param_array[$parname];
 307          }
 308  
 309          // Try default values:
 310          // Note we set 'infinite_loop' param to avoid calling the get_param() from the get_param_definitions() function recursively
 311          $params = $this->get_param_definitions( $check_infinite_loop ? array( 'infinite_loop' => true ) : NULL );
 312          if( isset( $params[$parname]['defaultvalue'] ) )
 313          {    // We ahve a default value:
 314              return $params[$parname]['defaultvalue'] ;
 315          }
 316  
 317          return NULL;
 318      }
 319  
 320  
 321      /**
 322       * Set param value
 323       *
 324       * @param string parameter name
 325       * @param mixed parameter value
 326       * @param boolean true to set to NULL if empty value
 327       * @return boolean true, if a value has been set; false if it has not changed
 328       */
 329  	function set( $parname, $parvalue, $make_null = false )
 330      {
 331          $params = $this->get_param_definitions( array( 'infinite_loop' => true ) );
 332  
 333          if( isset( $params[$parname] ) )
 334          { // This is a widget specific param:
 335              // Make sure param_array is loaded before set the param value
 336              $this->load_param_array();
 337              $this->param_array[$parname] = $parvalue;
 338              // This is what'll be saved to the DB:
 339              return $this->set_param( 'params', 'string', serialize($this->param_array), $make_null );
 340          }
 341  
 342          switch( $parname )
 343          {
 344              default:
 345                  return $this->set_param( $parname, 'string', $parvalue, $make_null );
 346          }
 347      }
 348  
 349  
 350      /**
 351       * Request all required css and js files for this widget
 352       */
 353  	function request_required_files()
 354      {
 355      }
 356  
 357  
 358      /**
 359       * Prepare display params
 360       *
 361       * @todo Document default params and default values.
 362       *       This might link to a wiki page, too.
 363       *
 364       * @param array MUST contain at least the basic display params
 365       */
 366  	function init_display( $params )
 367      {
 368          global $admin_url, $debug;
 369  
 370          if( !is_null($this->disp_params) )
 371          { // Params have been initialized before...
 372              return;
 373          }
 374  
 375          // Generate widget defaults array:
 376          $widget_defaults = array();
 377          $defs = $this->get_param_definitions( array() );
 378          foreach( $defs as $parname => $parmeta )
 379          {
 380              if( isset( $parmeta['defaultvalue'] ) )
 381              {
 382                  $widget_defaults[ $parname ] = $parmeta['defaultvalue'];
 383              }
 384              else
 385              {
 386                  $widget_defaults[ $parname ] = NULL;
 387              }
 388          }
 389  
 390          // Load DB configuration:
 391          $this->load_param_array();
 392  
 393          // Merge basic defaults < widget defaults < container params < DB params
 394          // note: when called with skin_widget it falls back to basic defaults < widget defaults < calltime params < array()
 395          $params = array_merge( array(
 396                      'block_start' => '<div class="$wi_class$">',
 397                      'block_end' => '</div>',
 398                      'block_display_title' => true,
 399                      'block_title_start' => '<h3>',
 400                      'block_title_end' => '</h3>',
 401                      'collist_start' => '',
 402                      'collist_end' => '',
 403                      'coll_start' => '<h4>',
 404                      'coll_end' => '</h4>',
 405                      'list_start' => '<ul>',
 406                      'list_end' => '</ul>',
 407                      'item_start' => '<li>',
 408                      'item_end' => '</li>',
 409                      'link_default_class' => 'default',
 410                      'link_selected_class' => 'selected',
 411                      'item_text_start' => '',
 412                      'item_text_end' => '',
 413                      'item_text' => '%s',
 414                      'item_selected_start' => '<li class="selected">',
 415                      'item_selected_end' => '</li>',
 416                      'item_selected_text' => '%s',
 417                      'item_last_start' => '<li class="last">',
 418                      'item_last_end' => '</li>',
 419                      'grid_start' => '<table cellspacing="1" class="widget_grid">',
 420                      'grid_end' => '</table>',
 421                      'grid_nb_cols' => 2,
 422                      'grid_colstart' => '<tr>',
 423                      'grid_colend' => '</tr>',
 424                      'grid_cellstart' => '<td>',
 425                      'grid_cellend' => '</td>',
 426                      'thumb_size' => 'crop-80x80',
 427                      // 'thumb_size' => 'fit-160x120',
 428                      'link_type' => 'canonic',        // 'canonic' | 'context' (context will regenrate URL injecting/replacing a single filter)
 429                      'item_selected_text_start' => '',
 430                      'item_selected_text_end' => '',
 431                      'group_start' => '<ul>',
 432                      'group_end' => '</ul>',
 433                      'notes_start' => '<div class="notes">',
 434                      'notes_end' => '</div>',
 435                      'tag_cloud_start' => '<p class="tag_cloud">',
 436                      'tag_cloud_end' => '</p>',
 437                      'limit' => 100,
 438                  ), $widget_defaults, $params, $this->param_array );
 439  
 440  
 441          // Customize params to the current widget:
 442          // add additional css classes if required
 443          $widget_css_class = 'widget_'.$this->type.'_'.$this->code.( empty( $params[ 'widget_css_class' ] ) ? '' : ' '.$params[ 'widget_css_class' ] );
 444          // add custom id if required, default to generic id for validation purposes
 445          $widget_ID = ( !empty($params[ 'widget_ID' ]) ? $params[ 'widget_ID' ] : 'widget_'.$this->type.'_'.$this->code.'_'.$this->ID );
 446          // replace the values
 447          $this->disp_params = str_replace( array( '$wi_ID$', '$wi_class$' ), array( $widget_ID, $widget_css_class ), $params );
 448      }
 449  
 450  
 451      /**
 452       * Display the widget!
 453       *
 454       * Should be overriden by core widgets
 455       *
 456       * @todo fp> handle custom params for each widget
 457       *
 458       * @param array MUST contain at least the basic display params
 459       */
 460  	function display( $params )
 461      {
 462          global $Blog;
 463          global $Plugins;
 464          global $rsc_url;
 465  
 466          $this->init_display( $params ); // just in case it hasn't been done before
 467  
 468          switch( $this->type )
 469          {
 470              case 'plugin':
 471                  // Call plugin (will return false if Plugin is not enabled):
 472                  if( $Plugins->call_by_code( $this->code, $this->disp_params ) )
 473                  {
 474                      return true;
 475                  }
 476                  // Plugin failed (happens when a plugin has been disabled for example):
 477                  return false;
 478          }
 479  
 480          echo "Widget $this->type : $this->code did not provide a display() method! ";
 481  
 482          return false;
 483      }
 484  
 485  
 486      /**
 487       * Wraps display in a cacheable block.
 488       *
 489       * @param array MUST contain at least the basic display params
 490       * @param array of extra keys to be used for cache keying
 491       */
 492  	function display_with_cache( $params, $keys = array() )
 493      {
 494          global $Blog, $Timer, $debug, $admin_url;
 495  
 496          $this->init_display( $params );
 497  
 498          if( ! $Blog->get_setting('cache_enabled_widgets')
 499              || ! $this->disp_params['allow_blockcache'] )
 500          {    // NO CACHING - We do NOT want caching for this collection or for this specific widget:
 501  
 502              if( $debug == 2 )
 503              {    // DEBUG:
 504                  echo '<div class="debug_widget"><div class="debug_widget_name" title="'.
 505                              ( $Blog->get_setting('cache_enabled_widgets') ? 'Widget params have BlockCache turned off' : 'Collection params have BlockCache turned off' ).'"><span class="debug_container_action"><a href="'
 506                              .$admin_url.'?ctrl=widgets&amp;action=edit&amp;wi_ID='.$this->ID.'">Edit</a></span>CACHE OFF: '.$this->get_name().'</div><div class="$wi_class$">'."\n";
 507              }
 508  
 509              $this->display( $params );
 510  
 511              if( $debug == 2 )
 512              {    // DEBUG:
 513                  echo "</div></div>\n";
 514              }
 515          }
 516          else
 517          {    // Instantiate BlockCache:
 518              $Timer->resume( 'BlockCache' );
 519              // Extend cache keys:
 520              $keys += $this->get_cache_keys();
 521  
 522              $this->BlockCache = new BlockCache( 'widget', $keys );
 523  
 524              $content = $this->BlockCache->check();
 525  
 526              $Timer->pause( 'BlockCache' );
 527  
 528              if( $content !== false )
 529              { // cache hit, let's display:
 530  
 531                  if( $debug == 2 )
 532                  {    // DEBUG:
 533                      echo '<div class="debug_widget widget_in_cache"><div class="debug_widget_name" title="'.$this->BlockCache->serialized_keys.'"><span class="debug_container_action"><a href="'
 534                                  .$admin_url.'?ctrl=widgets&amp;action=edit&amp;wi_ID='.$this->ID.'">Edit</a></span>FROM CACHE: '.$this->get_name().'</div><div class="$wi_class$">'."\n";
 535                  }
 536  
 537                  echo $content;
 538  
 539                  if( $debug == 2 )
 540                  {    // DEBUG:
 541                      echo "</div></div>\n";
 542                  }
 543  
 544              }
 545              else
 546              {    // Cache miss, we have to generate:
 547  
 548                  if( $debug == 2 )
 549                  {    // DEBUG:
 550                      echo '<div class="debug_widget widget_not_in_cache"><div class="debug_widget_name" title="'.$this->BlockCache->serialized_keys.'"><span class="debug_container_action"><a href="'
 551                                  .$admin_url.'?ctrl=widgets&amp;action=edit&amp;wi_ID='.$this->ID.'">Edit</a></span>NOT IN CACHE: '.$this->get_name().'</div><div class="$wi_class$">'."\n";
 552                  }
 553  
 554                  $this->BlockCache->start_collect();
 555  
 556                  $this->display( $params );
 557  
 558                  // Save collected cached data if needed:
 559                  $this->BlockCache->end_collect();
 560  
 561                  if( $debug == 2 )
 562                  {    // DEBUG:
 563                      echo "</div></div>\n";
 564                  }
 565  
 566              }
 567          }
 568      }
 569  
 570  
 571      /**
 572       * Maybe be overriden by some widgets, depending on what THEY depend on..
 573       *
 574       * @return array of keys this widget depends on
 575       */
 576  	function get_cache_keys()
 577      {
 578          global $Blog;
 579  
 580          return array(
 581                  'wi_ID'   => $this->ID,                // Have the widget settings changed ?
 582                  'set_coll_ID' => $Blog->ID,        // Have the settings of the blog changed ? (ex: new skin)
 583              );
 584      }
 585  
 586  
 587      /**
 588       * Note: a container can prevent display of titles with 'block_display_title'
 589       * This is useful for the lists in the headers
 590       * fp> I'm not sure if this param should be overridable by widgets themselves (priority problem)
 591       * Maybe an "auto" setting.
 592       *
 593       * @access protected
 594       */
 595  	function disp_title( $title = NULL, $display = true )
 596      {
 597          if( is_null($title) )
 598          {
 599              $title = & $this->disp_params['title'];
 600          }
 601  
 602          if( $this->disp_params['block_display_title'] && !empty( $title ) )
 603          {
 604              $r = $this->disp_params['block_title_start'];
 605              $r .= format_to_output( $title );
 606              $r .= $this->disp_params['block_title_end'];
 607  
 608              if( $display ) echo $r;
 609  
 610              return $r;
 611          }
 612      }
 613  
 614  
 615      /**
 616       * List of collections/blogs
 617       *
 618       * @param array MUST contain at least the basic display params
 619       */
 620  	function disp_coll_list( $filter = 'public', $order_by = 'ID', $order_dir = 'ASC' )
 621      {
 622          /**
 623           * @var Blog
 624           */
 625          global $Blog, $baseurl;
 626  
 627          echo $this->disp_params['block_start'];
 628  
 629          $this->disp_title();
 630  
 631          /**
 632           * @var BlogCache
 633           */
 634          $BlogCache = & get_BlogCache();
 635  
 636          if( $filter == 'owner' )
 637          {    // Load blogs of same owner
 638              $blog_array = $BlogCache->load_owner_blogs( $Blog->owner_user_ID, $order_by, $order_dir );
 639          }
 640          else
 641          {    // Load all public blogs
 642              $blog_array = $BlogCache->load_public( $order_by, $order_dir );
 643          }
 644  
 645          // 3.3? if( $this->disp_params['list_type'] == 'list' )
 646          // fp> TODO: init default value for $this->disp_params['list_type'] to avoid error
 647          {
 648              echo $this->disp_params['list_start'];
 649  
 650              foreach( $blog_array as $l_blog_ID )
 651              {    // Loop through all public blogs:
 652  
 653                  $l_Blog = & $BlogCache->get_by_ID( $l_blog_ID );
 654  
 655                  if( $Blog && $l_blog_ID == $Blog->ID )
 656                  { // This is the blog being displayed on this page:
 657                  echo $this->disp_params['item_selected_start'];
 658                      $link_class = $this->disp_params['link_selected_class'];
 659                  }
 660                  else
 661                  {
 662                      echo $this->disp_params['item_start'];
 663                      $link_class = $this->disp_params['link_default_class'];;
 664                  }
 665  
 666                  echo '<a href="'.$l_Blog->gen_blogurl().'" class="'.$link_class.'" title="'
 667                                              .$l_Blog->dget( 'name', 'htmlattr' ).'">';
 668  
 669                  if( $Blog && $l_blog_ID == $Blog->ID )
 670                  { // This is the blog being displayed on this page:
 671                      echo $this->disp_params['item_selected_text_start'];
 672                      printf( $this->disp_params['item_selected_text'], $l_Blog->dget( 'shortname', 'htmlbody' ) );
 673                      echo $this->disp_params['item_selected_text_end'];
 674                      echo '</a>';
 675                      echo $this->disp_params['item_selected_end'];
 676                  }
 677                  else
 678                  {
 679                      echo $this->disp_params['item_text_start'];
 680                      printf( $this->disp_params['item_text'], $l_Blog->dget( 'shortname', 'htmlbody' ) );
 681                      echo $this->disp_params['item_text_end'];
 682                      echo '</a>';
 683                      echo $this->disp_params['item_end'];
 684                  }
 685              }
 686  
 687              echo $this->disp_params['list_end'];
 688          }
 689          /* 3.3?
 690              Problems:
 691              -In FF3/XP with skin evoCamp, I click to drop down and it already reloads the page on the same blog.
 692              -Missing appropriate CSS so it displays at least half nicely in most of teh default skins
 693          {
 694              $select_options = '';
 695              foreach( $blog_array as $l_blog_ID )
 696              {    // Loop through all public blogs:
 697                  $l_Blog = & $BlogCache->get_by_ID( $l_blog_ID );
 698  
 699                  // Add item select list:
 700                  $select_options .= '<option value="'.$l_blog_ID.'"';
 701                  if( $Blog && $l_blog_ID == $Blog->ID )
 702                  {
 703                      $select_options .= ' selected="selected"';
 704                  }
 705                  $select_options .= '>'.$l_Blog->dget( 'shortname', 'formvalue' ).'</option>'."\n";
 706              }
 707  
 708              if( !empty($select_options) )
 709              {
 710                  echo '<form action="'.$baseurl.'" method="get">';
 711                  echo '<select name="blog" onchange="this.form.submit();">'.$select_options.'</select>';
 712                  echo '<noscript><input type="submit" value="'.T_('Go').'" /></noscript></form>';
 713              }
 714          }
 715          */
 716          echo $this->disp_params['block_end'];
 717      }
 718  
 719  
 720      /**
 721       * Insert object into DB based on previously recorded changes.
 722       *
 723       * @return boolean true on success
 724       */
 725  	function dbinsert()
 726      {
 727          global $DB;
 728  
 729          if( $this->ID != 0 )
 730          {
 731              debug_die( 'Existing object cannot be inserted!' );
 732          }
 733  
 734          $DB->begin();
 735  
 736          $order_max = $DB->get_var(
 737              'SELECT MAX(wi_order)
 738                   FROM T_widget
 739                  WHERE wi_coll_ID = '.$this->coll_ID.'
 740                      AND wi_sco_name = '.$DB->quote($this->sco_name), 0, 0, 'Get current max order' );
 741  
 742          $this->set( 'order', $order_max+1 );
 743  
 744          $res = parent::dbinsert();
 745  
 746          $DB->commit();
 747  
 748          return $res;
 749      }
 750  
 751  
 752      /**
 753       * Update the DB based on previously recorded changes
 754       */
 755  	function dbupdate()
 756      {
 757          global $DB;
 758  
 759          parent::dbupdate();
 760  
 761          // This widget has been modified, cached content depending on it should be invalidated:
 762          BlockCache::invalidate_key( 'wi_ID', $this->ID );
 763      }
 764  
 765  }
 766  
 767  ?>

title

Description

title

Description

title

Description

title

title

Body