File Manager

Current Path : /webspace/www.saveursetterroir.be/html/lib/classes/
Upload File :
Current File : //webspace/www.saveursetterroir.be/html/lib/classes/class.ContentBase.php

<?php
# CMS - CMS Made Simple
# (c)2004 by Ted Kulp (tedkulp@users.sf.net)
# This project's homepage is: http://www.cmsmadesimple.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# BUT withOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
#$Id: class.content.inc.php 6905 2011-02-20 22:23:40Z calguy1000 $

/**
 * @package CMS
 */

/**
 * @ignore
 */
define('CMS_CONTENT_HIDDEN_NAME','--------');

/**
 * Generic content class.
 *
 * As for some treatment we don't need the extra properties of the content
 * we load them only when required. However, each function which makes use
 * of extra properties should first test if the properties object exist.
 *
 * @since		0.8
 * @package		CMS
 */
abstract class ContentBase
{
  /**
   * The unique ID identifier of the element
   * Integer
   *
   * @internal
   */
  protected $mId = -1;

  /**
   * The name of the element (like a filename)
   * String
   */
  protected $mName = '';

  /**
   * The type of content (page, url, etc..)
   * String
   *
   * @internal
   */
  protected $mType = '';

  /**
   * The owner of the content
   * Integer
   *
   * @internal
   */
  protected $mOwner = -1;

  /**
   * The properties part of the content. This is an object of the good type.
   * It should contain all treatments specific to this type of content
   *
   * @internal
   */
  protected $_props;

  /**
   * The ID of the parent, 0 if none
   * Integer
   */
  protected $mParentId = -2;

  /**
   * The old parent id... only used on update
   *
   * @internal
   */
  protected $mOldParentId = -1;

  /**
   * This is used too often to not be part of the base class
   *
   * @internal
   */
  protected $mTemplateId = -1;

  /**
   * The item order of the content in his level
   * Integer
   */
  protected $mItemOrder = -1;

  /**
   * The old item order... only used on update
   *
   * @internal
   */
  protected $mOldItemOrder = -1;

  /**
   * The metadata (head tags) fir this content
   *
   * @internal
   */
  protected $mMetadata = '';

  /**
   * @internal
   */
  protected $mTitleAttribute = '';

  /**
   * @internal
   */
  protected $mAccessKey = '';

  /**
   * @internal
   */
  protected $mTabIndex = '';

  /**
   * The full hierarchy of the content
   * String of the form : 1.4.3
   */
  protected $mHierarchy = '';

  /**
   * The full hierarchy of the content ids
   * String of the form : 1.4.3
   */
  protected $mIdHierarchy = '';

  /**
   * The full path through the hierarchy
   * String of the form : parent/parent/child
   *
   * @internal
   */
  protected $mHierarchyPath = '';

  /**
   * What should be displayed in a menu
   *
   * @internal
   */
  protected $mMenuText = '';

  /**
   * Is the content active ?
   * Integer : 0 / 1
   *
   * @internal
   */
  protected $mActive = false;

  /**
   * Alias of the content
   *
   * @internal
   */
  protected $mAlias;

  /**
   * Old Alias of the content
   *
   * @internal
   */
  protected $mOldAlias;

  /**
   * Cachable?
   *
   * @internal
   */
  protected $mCachable;

  /**
   * Secure?
   *
   * @internal
   */
  protected $mSecure = 0;

  /**
   * URL
   *
   * @internal
   */
  protected $mURL = '';

  /**
   * Does this content have a preview function?
   *
   * @internal
   */
  protected $mPreview = '';

  /**
   * Should it show up in the menu?
   *
   * @internal
   */
  protected $mShowInMenu = false;

  /**
   * Is this page the default?
   *
   * @internal
   */
  protected $mDefaultContent = false;
	
  /**
   * What type of markup is ths?  HTML is the default
   */
  protected $mMarkup = 'html';

  /**
   * Last user to modify this content
   *
   * @internal
   */
  protected $mLastModifiedBy = -1;

  /**
   * Creation date
   * Date
   *
   * @internal
   */
  protected $mCreationDate = '';

  /**
   * Modification date
   * Date
   *
   * @internal
   */
  protected $mModifiedDate = '';
    
  /**
   * Additional Editors Array
   *
   * @internal
   */
  protected $mAdditionalEditors;
	
  /*
   * state or meta information
   *
   * @internal
   */
  protected $mReadyForEdit;

  private $_attributes;
  private $_prop_defaults;
  private $_add_mode;
  private $_error;

  /************************************************************************/
  /* Constructor related													*/
  /************************************************************************/

  /**
   * Generic constructor. Runs the SetInitialValues fuction.
   */
  public function __construct()
  {
    $this->SetInitialValues();
    $this->SetProperties();
    $this->mReadyForEdit = false;
  }

  /**
   * Sets object to some sane initial values
   *
   * @internal
   */
  protected function SetInitialValues()
  {
    $this->mType = strtolower(get_class($this)) ;
  }

  /**
   * Subclasses should override this to set their property types using a lot
   * of mProperties.Add statements
   */
  protected function SetProperties()
  {
    $this->AddBaseProperty('title',1,1);
    $this->AddBaseProperty('menutext',2,1);
    $this->AddBaseProperty('alias',5);
    $this->AddBaseProperty('page_url',6);
    $this->AddBaseProperty('parent',7,1);
    $this->AddBaseProperty('active',8);
    $this->AddBaseProperty('showinmenu',9);
    $this->AddBaseProperty('secure',10);
    $this->AddBaseProperty('cachable',11);
    $this->AddContentProperty('target',12);
      
    $this->AddContentProperty('image',50);
    $this->AddContentProperty('thumbnail',50);
    $this->AddBaseProperty('titleattribute',55);
    $this->AddBaseProperty('accesskey',56);
    $this->AddBaseProperty('tabindex',57);
	  
    $this->AddContentProperty('extra1',80);
    $this->AddContentProperty('extra2',81);
    $this->AddContentProperty('extra3',82);
	  
    $this->AddBaseProperty('owner',90);
    $this->AddBaseProperty('additionaleditors',91);
  }

    
  /************************************************************************/
  /* Functions giving access to needed elements of the content			*/
  /************************************************************************/
  
  public function __clone()
  {
    $this->mId = -1;
    $this->mItemOrder = -1;
    $this->mOldItemOrder = -1;
    $this->mURL = '';
    $this->mAlias = '';
  }

  /**
   * Returns the ID
   */
  public function Id()
  {
    return $this->mId;
  }

  /**
   * Set the numeric id of the content item
   *
   * @param integer Integer id
   * @access private
   * @internal
   */
  public function SetId($id)
  {
    if( $id <= 0 ) return;
    $this->mId = $id;
    $this->DoReadyForEdit();
  }

  /**
   * Returns a friendly name for this content type
   *
   * @abstract
   * @return string
   */
  public function FriendlyName()
  {
    return '';
  }

  /**
   * Returns the Name
   *
   * @return string
   */
  public function Name()
  {
    return $this->mName;
  }

  /**
   * Set the the page name
   *
   * @param string The name.
   */
  public function SetName($name)
  {
    $this->DoReadyForEdit();
    $this->mName = $name;
  }

  /**
   * Returns the Alias
   *
   * @return string
   */
  public function Alias()
  {
    return $this->mAlias;
  }

  /**
   * Returns the Type
   *
   * @return string
   */
  public function Type()
  {
    return strtolower($this->mType);
  }

  /**
   * Set the page type
   *
   * @param string type
   * @abstract
   * @internal
   */
  protected function SetType($type)
  {
    $this->DoReadyForEdit();
    $this->mType = strtolower($type);
  }

  /**
   * Returns the Owner
   *
   * @return integer
   */
  public function Owner()
  {
    return $this->mOwner;
  }

  /**
   * Set the page owner.
   * No validation is performed.
   *
   * @param integer Owner's user id
   */
  public function SetOwner($owner)
  {
    if( $owner <= 0 ) return;
    $this->DoReadyForEdit();
    $this->mOwner = $owner;
  }

  /**
   * Returns the Metadata
   *
   * @return string
   */
  public function Metadata()
  {
    return $this->mMetadata;
  }

  /**
   * Content object handles the alias
   *
   * @return boolean
   */
  public function HandlesAlias()
  {
    return false;
  }

  /**
   * Set the page metadata
   * 
   * @param string The metadata
   */
  public function SetMetadata($metadata)
  {
    $this->DoReadyForEdit();
    $this->mMetadata = $metadata;
  }

  /**
   * Return the page tabindex value
   *
   * @return integer
   */
  public function TabIndex()
  {
    return $this->mTabIndex;
  }

  /**
   * Set the page tabindex value
   *
   * @param integer tabindex
   */
  public function SetTabIndex($tabindex)
  {
    $this->DoReadyForEdit();
    $this->mTabIndex = $tabindex;
  }

  /**
   * Return the page title attribute
   *
   * @return string
   */
  public function TitleAttribute()
  {
    return $this->mTitleAttribute;
  }

  /**
   * Retrieve the creation date of this content object.
   *
   * @return int Unix Timestamp of the creation date
   */
  public function GetCreationDate()
  {
    return strtotime($this->mCreationDate);
  }

  /**
   * Retrieve the date of the last modification of this content object.
   *
   * @return int Unix Timestamp of the modification date.
   */
  public function GetModifiedDate()
  {
    return strtotime($this->mModifiedDate);
  }


  /**
   * Set the title attribute of the page
   *
   * @param string The title attribute
   */
  public function SetTitleAttribute($titleattribute)
  {
    $this->DoReadyForEdit();
    $this->mTitleAttribute = $titleattribute;
  }

  /**
   * Get the access key (for accessibility) for this page.
   *
   * @return string
   */
  public function AccessKey()
  {
    return $this->mAccessKey;
  }

  /**
   * Set the access key (for accessibility) for this page
   *
   * @param string Access Key
   */
  public function SetAccessKey($accesskey)
  {
    $this->DoReadyForEdit();
    $this->mAccessKey = $accesskey;
  }

  /**
   * Returns the id of this pages parent.
   *
   * @return int -1 if this page has no parent.  Positive integer otherwise.
   */
  public function ParentId()
  {
    return $this->mParentId;
  }

  /**
   * Sets the parent of this page.
   *
   * @param int The numeric page parent id.  Use -1 for no parent.
   */
  public function SetParentId($parentid)
  {
    $this->DoReadyForEdit();
    $this->mParentId = $parentid;
  }

  /**
   * Retrieve the 'old parent id' for this page.
   * This may return a value if the page's parent has changed or the page has been copied.
   *
   * @deprecated
   * @internal
   * @return integer
   */
   public function OldParentId()
   {
     return $this->mOldParentId;
   }

   /**
    * Sets the OldParentId value for this page
    * This may be necessary when changin page ownership or copying a page
    *
    * @deprecated
    * @internal
    * @param int ParentID ... -1 indicates no parent.
    */
   public function SetOldParentId($parentid)
   {
     $this->DoReadyForEdit();
     $this->mOldParentId = $parentid;
   }

   /**
    * Return the id of the page template associated with this content page.
    *
    * @return integer.
    */
   public function TemplateId()
   {
     return $this->mTemplateId;
   }

   /**
    * Set the id of the page template associated with this content page.
    *
    * @param integer
    */
   public function SetTemplateId($templateid)
   {
     $this->DoReadyForEdit();
     $this->mTemplateId = $templateid;
   }

   /**
    * Returns the ItemOrder
    * The ItemOrder is used to specify the order of this page within the parent.
    *
    * @return int
    */
   public function ItemOrder()
   {
     return $this->mItemOrder;
   }

   /**
    * Sets the ItemOrder
    * The ItemOrder is used to specify the order of this page within the parent.
    *
    * @internal
    * @param int the itemorder.
    */
   public function SetItemOrder($itemorder)
   {
     $this->DoReadyForEdit();
     $this->mItemOrder = $itemorder;
   }

   /**
    * Return the old item order.
    *
    * @deprecated
    * @internal
    * @return int
    */
   public function OldItemOrder()
   {
     return $this->mOldItemOrder;
   }

   /**
    * Sets the old item order.
    *
    * @deprecated
    * @internal
    * @param int The item order.
    */
   public function SetOldItemOrder($itemorder)
   {
     $this->DoReadyForEdit();
     $this->mOldItemOrder = $itemorder;
   }

   /**
    * Returns the Hierarchy
    *
    * @return string
    */
   public function Hierarchy()
   {
      $gCms = cmsms();
      $contentops = $gCms->GetContentOperations();
      return $contentops->CreateFriendlyHierarchyPosition($this->mHierarchy);
   }

   /**
    * Sets the Hierarchy
    *
    * @internal
    * @param string
    */
   public function SetHierarchy($hierarchy)
   {
     $this->DoReadyForEdit();
     $this->mHierarchy = $hierarchy;
   }

   /**
    * Returns the Id Hierarchy
    *
    * @return string
    */
   public function IdHierarchy()
   {
     return $this->mIdHierarchy;
   }


   /**
    * Sets the Id Hierarchy
    *
    * @internal
    * @param string
    */
   public function SetIdHierarchy($idhierarchy)
   {
     $this->DoReadyForEdit();
     $this->mIdHierarchy = $idhierarchy;
   }


   /**
    * Returns the Hierarchy Path
    *
    * @return string
    */
   public function HierarchyPath()
   {
     return $this->mHierarchyPath;
   }


   /**
    * Sets the Hierarchy Path
    *
    * @internal
    * @param string
    */
   public function SetHierarchyPath($hierarchypath)
   {
     $this->DoReadyForEdit();
     $this->mHierarchyPath = $hierarchypath;
   }
   

   /**
    * Returns the Active state
    *
    * @return boolean
    */
   public function Active()
   {
     return $this->mActive;
   }


   /**
    * Sets this page as active
    *
    * @param boolean
    */
   public function SetActive($active)
   {
     $this->DoReadyForEdit();
     $this->mActive = $active;
   }


   /**
    * Returns whether preview should be available for this content type
    *
    * @abstract
    * @return boolean
    */
   public function HasPreview()
   {
     return (bool) $this->mPreview;
   }


   /**
    * Returns whether it should show in the menu
    *
    * @return boolean
    */
   public function ShowInMenu()
   {
     return $this->mShowInMenu;
   }


   /**
    * Sets whether this page should be shown in menus
    *
    * @param boolean
    */
   public function SetShowInMenu($showinmenu)
   {
     $this->DoReadyForEdit();
     $this->mShowInMenu = $showinmenu;
   }


   /**
    * Returns if the page is the default
    *
    * @return boolean
    */
   public function DefaultContent()
   {
     return $this->mDefaultContent;
   }

   /**
    * Sets if this page should be considered the default
    * Note: does not modify the flags for any other content page.
    *
    * @param boolean
    */
   public function SetDefaultContent($defaultcontent)
   {
     $this->DoReadyForEdit();
     $this->mDefaultContent = $defaultcontent;
   }


   /**
    * Return wether this page is cachable
    *
    * @return boolean
    */
   public function Cachable()
   {
     return $this->mCachable;
   }


   /**
    * Set wether this page is cachable
    *
    * @param boolean
    */
    public function SetCachable($cachable)
    {
	$this->DoReadyForEdit();
	$this->mCachable = $cachable;
    }


   /**
    * Return wether this page should be accessed via a secure protocol.
    * The secure flag effectsw wether the ssl protocol and appropriate config entries are used when generating urls to this page.
    *
    * @return boolean
    */
    public function Secure()
    {
      return $this->mSecure;
    }


   /**
    * Set wether this page should be accessed via a secure protocol.
    * The secure flag effectsw wether the ssl protocol and appropriate config entries are used when generating urls to this page.
    *
    * @return boolean
    */
    public function SetSecure($secure)
    {
	$this->DoReadyForEdit();
	$this->mSecure = $secure;
    }
	
    
    /**
     * Return the page url (if any) associated with this content page.
     * Note: some content types do not support page urls.
     *
     * @return string
     */
    public function URL()
    {
      return $this->mURL;
    }

    /**
     * Set the page url (if any) associated with this content page.
     * Note: some content types do not support page urls.
     * The url should be relative to the root url.  i.e: /some/path/to/the/page
     *
     * @param string
     */
    public function SetURL($url)
    {
      $this->DoReadyForEdit();
      $this->mURL = $url;
    }

    /**
     * Return the markup for this page. usually xhtml or html.
     * 
     * @deprecated
     * @return string
     */
    public function Markup()
    {
      return $this->mMarkup;
    }

    /**
     * Set the markup for this page. usually xhtml or html.
     * 
     * @deprecated
     * @param string
     */
    public function SetMarkup($markup)
    {
      $this->DoReadyForEdit();
      $this->mMarkup = $markup;
    }

    /**
     * Return the last modified date for this item
     * This is usually set on save.
     * 
     * @return Date
     */
    public function LastModifiedBy()
    {
      return $this->mLastModifiedBy;
    }

    /**
     * Set the last modified date for this item
     * This is usually set on save.
     * 
     * @param Date
     */
    public function SetLastModifiedBy($lastmodifiedby)
    {
      $this->DoReadyForEdit();
      $this->mLastModifiedBy = $lastmodifiedby;
    }

    /**
     * Indicates wether this content type requires an alias
     *
     * @abstract
     * @return boolean
     */
    public function RequiresAlias()
    {
      return TRUE;
    }

    /**
     * Indicates wether this content type is viewable (i.e: can be rendered)
     * some content types (like redirection links) are not viewable.
     *
     * @abstract
     * @return boolean
     */
    public function IsViewable()
    {
      return TRUE;
    }


    /**
     * Set the page alias for this content page.  
     * If an empty alias is supplied, and depending upon the doAutoAliasIfEnabled flag, and config entries
     * a suitable alias may be calculated from other data in the page object
     * This method relies on the menutext and the name of the content page already being set.
     *
     * @param string The alias
     * @param boolean Wether an alias should be calculated or not.
     */
    public function SetAlias($alias, $doAutoAliasIfEnabled = true)
    {
      $this->DoReadyForEdit();
      $gCms = cmsms();
      $config = $gCms->GetConfig();

      $tolower = false;

      if ($alias == '' && $doAutoAliasIfEnabled && $config['auto_alias_content'] == true)
	{
	  $alias = trim($this->mMenuText);
	  if ($alias == '')
	    {
	      $alias = trim($this->mName);
	    }
			
	  $tolower = true;
	  $alias = munge_string_to_url($alias, $tolower);
	  // Make sure auto-generated new alias is not already in use on a different page, if it does, add "-2" to the alias
	  $contentops = $gCms->GetContentOperations();
	  $error = $contentops->CheckAliasError($alias, $this->Id());
	  if ($error !== FALSE)
	    {
	      if (FALSE == empty($alias))
		{
		  $alias_num_add = 2;
		  // If a '-2' version of the alias already exists
		  // Check the '-3' version etc.
		  while ($contentops->CheckAliasError($alias.'-'.$alias_num_add) !== FALSE)
		    {
		      $alias_num_add++;
		    }
		  $alias .= '-'.$alias_num_add;
		}
	      else
		{
		  $alias = '';
		}
	    }
	}

      $this->mAlias = munge_string_to_url($alias, $tolower);
    } 

	
    /**
     * Returns the menu text for this content page
     *
     * @return string
     */
    public function MenuText()
    {
      return $this->mMenuText;
    }

    /**
     * Sets the menu text for this content page
     *
     * @param string
     */
    public function SetMenuText($menutext)
    {
      $this->DoReadyForEdit();
      $this->mMenuText = $menutext;
    }

    /**
     * Returns number of immediate child-content items of this content
     *
     * @return integer
     */
    public function ChildCount()
    {
      $hm = cmsms()->GetHierarchyManager();
      $node = $hm->getNodeById($this->mId);
      if( $node )
	{
	  return $node->count_children();
	}
    }

    /**
     * Returns the properties
     *
     * @return array
     */
    public function Properties()
    {
      return $this->_props;
    }

    /**
     * Test wether this content page has the named property
     * Properties will be loaded from the database if necessary.
     *
     * @return boolean
     */
    public function HasProperty($name)
    {
      if( !is_array($this->_props) ) {
	$this->_load_properties();
      }
      if( !is_array($this->_props) ) {
	return FALSE;
      }
      return in_array($name,array_keys($this->_props));
    }

    
    /**
     * Get the value for the named property
     *
     * @return mixed String value, or null if the property does not exist.
     */
    public function GetPropertyValue($name)
    {
      if( $this->HasProperty($name) )
	{
	  return $this->_props[$name];
	}
    }
    
    
    private function _load_properties()
    {
      if( $this->mId <= 0 ) return FALSE;

      $this->_props = array();
      $db = cmsms()->GetDb();
      $query = 'SELECT * FROM '.cms_db_prefix().'content_props WHERE content_id = ?';
      $dbr = $db->Execute($query,array($this->mId));
      while( $dbr && !$dbr->EOF )
	{
	  $row = $dbr->fields;
	  $this->_props[$row['prop_name']] = $row['content'];
	  $dbr->MoveNext();
	}
      return TRUE;
    }

    private function _save_properties()
    {
      if( $this->mId <= 0 ) return FALSE;
      if( !is_array($this->_props) || count($this->_props) == 0 ) return FALSE;
	    
      $db = cmsms()->GetDb();
      $query = 'SELECT prop_name FROM '.cms_db_prefix().'content_props WHERE content_id = ?';
      $gotprops = $db->GetCol($query,array($this->mId));

      $now = $db->DbTimeStamp(time());
      $iquery = 'INSERT INTO '.cms_db_prefix()."content_props
                    (content_id,type,prop_name,content,modified_date)
                    VALUES (?,?,?,?,$now)";
      $uquery = 'UPDATE '.cms_db_prefix()."content_props SET content = ?, modified_date = $now WHERE content_id = ? AND prop_name = ?";
	  
      foreach( $this->_props as $key => $value )
	{
	  if( in_array($key,$gotprops) )
	    {
	      // update
	      $dbr = $db->Execute($uquery,array($value,$this->mId,$key));
	    }
	  else
	    {
	      // insert
	      $dbr = $db->Execute($iquery,array($this->mId,'string',$key,$value));
	    }
	}
      return TRUE;
    }

    /**
     * Set the value of a the named property.
     * This method will load properties for this content page if necessary.
     *
     * @param string The property name
     * @param string  The property value.
     */
    public function SetPropertyValue($name, $value)
    {
      if( !is_array($this->_props) ) $this->_props = array();
	  
      $this->_props[$name] = $value;
      if( !is_array($this->_props) ) $this->_load_properties();
      $this->_props[$name] = $value;
    }
	
    /**
     * Set the value of a the named property.
     * This method will not load properties
     *
     * @param string The property name
     * @param string  The property value.
     */
    public function SetPropertyValueNoLoad($name,$value)
    {
      if( !is_array($this->_props) ) $this->_props = array();
      $this->_props[$name] = $value;
    }

    /**
     * Function content types to use to say whether or not they should show
     * up in lists where parents of content are set.  This will default to true,
     * but should be used in cases like Separator where you don't want it to 
     * have any children.
     * 
     * @since 0.11
     * @return boolean
     */
    public function WantsChildren()
    {
      return true;
    }

    /**
     * Should this link be used in various places where a link is the only
     * useful output?  (Like next/previous links in cms_selflink, for example)
     *
     * @abstract
     * @return boolean
     */
    public function HasUsableLink()
    {
      return true;
    }

    /**
     * Is this content type copyable ?
     *
     * @abstract
     * @return boolean
     */
    public function IsCopyable()
    {
      return FALSE;
    }

    /**
     * Indicates wether this is a system page type.
     *
     * @return boolean
     */
    public function IsSystemPage()
    {
      return FALSE;
    }

    /************************************************************************/
    /* The rest																*/
    /************************************************************************/

    /**
     * This is a callback function to handle any things that might need to be done before the content page is edited.
     * edited.
     *
     * @abstract
     * @return void
     */
    public function ReadyForEdit()
    {
    }

    /**
     * A method that sets the content page into a 'ready for edit stage';
     *
     * @return void
     */
    protected function DoReadyForEdit()
    {
      if ($this->mReadyForEdit == false)
	{
	  $this->ReadyForEdit();
	  $this->mReadyForEdit = true;
	}
    }
    
    /**
     * Load the content of the object from an ID
     * This method modifies the current object.
     *
     * @param $id		the ID of the element
     * @param $loadProperties	whether to load or not the properties
     *
     * @returns bool		If it fails, the object comes back to initial values and returns FALSE
     *				If everything goes well, it returns TRUE
     */
    public function LoadFromId($id, $loadProperties = false)
    {
      $gCms = cmsms();
      global $debug_errors;
      $db = $gCms->GetDb();
      $config = $gCms->GetConfig();
	  
      $result = false;

      if (-1 < $id)
	{
	  $query = "SELECT * FROM ".cms_db_prefix()."content WHERE content_id = ?";
	  $row = $db->Execute($query, array($id));

	  if ($row && !$row->EOF)
	    {
	      $this->mId                         = $row->fields["content_id"];
	      $this->mName                       = $row->fields["content_name"];
	      $this->mAlias                      = $row->fields["content_alias"];
	      $this->mOldAlias                   = $row->fields["content_alias"];
	      $this->mType                       = strtolower($row->fields["type"]);
	      $this->mOwner                      = $row->fields["owner_id"];
	      $this->mParentId                   = $row->fields["parent_id"];
	      $this->mOldParentId                = $row->fields["parent_id"];
	      $this->mTemplateId                 = $row->fields["template_id"];
	      $this->mItemOrder                  = $row->fields["item_order"];
	      $this->mOldItemOrder               = $row->fields["item_order"];
	      $this->mMetadata                   = $row->fields['metadata'];
	      $this->mHierarchy                  = $row->fields["hierarchy"];
	      $this->mIdHierarchy                = $row->fields["id_hierarchy"];
	      $this->mHierarchyPath              = $row->fields["hierarchy_path"];
	      $this->mMenuText                   = $row->fields['menu_text'];
	      $this->mMarkup                     = $row->fields['markup'];
	      $this->mTitleAttribute             = $row->fields['titleattribute'];
	      $this->mAccessKey                  = $row->fields['accesskey'];
	      $this->mTabIndex                   = $row->fields['tabindex'];
	      $this->mActive                     = ($row->fields["active"] == 1          ? true : false);
	      $this->mDefaultContent             = ($row->fields["default_content"] == 1 ? true : false);
	      $this->mShowInMenu                 = ($row->fields["show_in_menu"] == 1    ? true : false);
	      $this->mCachable                   = ($row->fields["cachable"] == 1        ? true : false);
	      $this->mSecure                     = $row->fields['secure'];
	      $this->mURL                        = $row->fields['page_url'];
	      $this->mLastModifiedBy             = $row->fields["last_modified_by"];
	      $this->mCreationDate               = $row->fields["create_date"];
	      $this->mModifiedDate               = $row->fields["modified_date"];

	      $result = true;
	    }
	  else
	    {
	      if (true == $config["debug"])
		{
		  # :TODO: Translate the error message
		  $debug_errors .= "<p>Could not retrieve content from db</p>\n";
		}
	    }

	  if ($row) $row->Close();

	  if ($result && $loadProperties)
	    {
	      if( !is_array($this->_props) ) $this->_load_properties();

	      if (!is_array($this->_props) )
		{
		  $result = false;
			      
		  // debug mode
		  if (true == $config["debug"])
		    {
		      # :TODO: Translate the error message
		      $debug_errors .= "<p>Could not load properties for content</p>\n";
		    }
		}
	    }

	  if (false == $result)
	    {
	      $this->SetInitialValues();
	    }
	}
      else
	{
	  // debug mode
	  if ($config["debug"] == true)
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>The id wasn't valid : $id</p>\n";
	    }
	}

      $this->Load();

      return $result;
    }

    /**
     * Load the content of the object from an array
     * This method modifies the current object.
     *
     * There is no check on the data provided, because this is the job of
     * ValidateData
     *
     * @returns	bool		If it fails, the object comes back to initial values and returns FALSE
     *				If everything goes well, it returns TRUE
     */
    function LoadFromData(&$data, $loadProperties = false)
    {
      $result = true;
      $this->mId                         = $data["content_id"];
      $this->mName                       = $data["content_name"];
      $this->mAlias                      = $data["content_alias"];
      $this->mOldAlias                   = $data["content_alias"];
      $this->mType                       = strtolower($data["type"]);
      $this->mOwner                      = $data["owner_id"];
      $this->mParentId                   = $data["parent_id"];
      $this->mOldParentId                = $data["parent_id"];
      $this->mTemplateId                 = $data["template_id"];
      $this->mItemOrder                  = $data["item_order"];
      $this->mOldItemOrder               = $data["item_order"];
      $this->mMetadata                   = $data['metadata'];
      $this->mHierarchy                  = $data["hierarchy"];
      $this->mIdHierarchy                = $data["id_hierarchy"];
      $this->mHierarchyPath              = $data["hierarchy_path"];
      $this->mMenuText                   = $data['menu_text'];
      $this->mMarkup                     = $data['markup'];
      $this->mTitleAttribute             = $data['titleattribute'];
      $this->mAccessKey                  = $data['accesskey'];
      $this->mTabIndex                   = $data['tabindex'];
      $this->mDefaultContent             = ($data["default_content"] == 1 ? true : false);
      $this->mActive                     = ($data["active"] == 1          ? true : false);
      $this->mShowInMenu                 = ($data["show_in_menu"] == 1    ? true : false);
      $this->mCachable                   = ($data["cachable"] == 1        ? true : false);
      if( isset($data['secure']) )
	$this->mSecure                   = $data["secure"];
      if( isset($data['page_url']) )
	$this->mURL                      = $data["page_url"];
      $this->mLastModifiedBy             = $data["last_modified_by"];
      $this->mCreationDate               = $data["create_date"];
      $this->mModifiedDate               = $data["modified_date"];

      if ($loadProperties == true)
	{
	  $this->_load_properties();

	  if (!is_array($this->_props) )
	    {
	      $result = false;
		      
	      global $debug_errors;
	      $gCms = cmsms();
	      $config = $gCms->GetConfig();
	      // debug mode
	      if (true == $config["debug"])
		{
		  # :TODO: Translate the error message
		  $debug_errors .= "<p>Could not load properties for content</p>\n";
		}
	    }
	}

      if (false == $result)
	{
	  $this->SetInitialValues();
	}

      $this->Load();

      return $result;
    }

    /**
     * Callback function for content types to use to preload content or other things if necessary.  This
     * is called right after the content is loaded from the database.
     *
     */
    protected function Load()
    {
    }

    /**
     * Save or update the content
     *
     * @todo This function should return something (or throw an exception)
     */
    function Save()
    {
      Events::SendEvent('Core', 'ContentEditPre', array('content' => &$this));

      if( !is_array($this->_props) )
	{
	  debug_buffer('save is loading properties');
	  $this->_load_properties();
	}

      if (-1 < $this->mId)
	{
	  $this->Update();
	}
      else
	{
	  $this->Insert();
	}

      Events::SendEvent('Core', 'ContentEditPost', array('content' => &$this));
    }

    /**
     * Update the content
     * We can notice, that only a few things are updated
     * We do not care about hierarchy for example. This is because hierarchy,
     * order or parents management is the job of the content manager.
     * Remember that a content is like a file, and a file don't know where it is
     * on the disk, it only knows its own content. It's the same here.
     *
     * @todo this function should return something, or throw an exception.
     */
    protected function Update()
    {
      $gCms = cmsms();
      global $debug_errors;
      $db = $gCms->GetDb();
      $config = $gCms->GetConfig();

      $result = false;

#Figure out the item_order (if necessary)
      if ($this->mItemOrder < 1)
	{
	  $query = "SELECT ".$db->IfNull('max(item_order)','0')." as new_order FROM ".cms_db_prefix()."content WHERE parent_id = ?";
	  $row = $db->GetRow($query,array($this->mParentId));

	  if ($row)
	    {
	      if ($row['new_order'] < 1)
		{
		  $this->mItemOrder = 1;
		}
	      else
		{
		  $this->mItemOrder = $row['new_order'] + 1;
		}
	    }
	}

      $this->mModifiedDate = trim($db->DBTimeStamp(time()), "'");

      $query = "UPDATE ".cms_db_prefix()."content SET content_name = ?, owner_id = ?, type = ?, template_id = ?, parent_id = ?, active = ?, default_content = ?, show_in_menu = ?, cachable = ?, secure = ?, page_url = ?, menu_text = ?, content_alias = ?, metadata = ?, titleattribute = ?, accesskey = ?, tabindex = ?, modified_date = ?, item_order = ?, markup = ?, last_modified_by = ? WHERE content_id = ?";
      $dbresult = $db->Execute($query, array(
					     $this->mName,
					     $this->mOwner,
					     strtolower($this->mType),
					     $this->mTemplateId,
					     $this->mParentId,
					     ($this->mActive == true         ? 1 : 0),
					     ($this->mDefaultContent == true ? 1 : 0),
					     ($this->mShowInMenu == true     ? 1 : 0),
					     ($this->mCachable == true       ? 1 : 0),
					     $this->mSecure,
					     $this->mURL,
					     $this->mMenuText,
					     $this->mAlias,
					     $this->mMetadata,
					     $this->mTitleAttribute,
					     $this->mAccessKey,
					     $this->mTabIndex,
					     $this->mModifiedDate,
					     $this->mItemOrder,
					     $this->mMarkup,
					     $this->mLastModifiedBy,
					     $this->mId
					     ));

      if (!$dbresult)
	{
	  if (true == $config["debug"])
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>Error updating content</p>\n";
	    }
	}

      if ($this->mOldParentId != $this->mParentId)
	{
#Fix the item_order if necessary
	  $query = "UPDATE ".cms_db_prefix()."content SET item_order = item_order - 1 WHERE parent_id = ? AND item_order > ?";
	  $result = $db->Execute($query, array($this->mOldParentId,$this->mOldItemOrder));

	  $this->mOldParentId = $this->mParentId;
	  $this->mOldItemOrder = $this->mItemOrder;
	}

      if (isset($this->mAdditionalEditors))
	{
	  $query = "DELETE FROM ".cms_db_prefix()."additional_users WHERE content_id = ?";
	  $db->Execute($query, array($this->Id()));

	  foreach ($this->mAdditionalEditors as $oneeditor)
	    {
	      $new_addt_id = $db->GenID(cms_db_prefix()."additional_users_seq");
	      $query = "INSERT INTO ".cms_db_prefix()."additional_users (additional_users_id, user_id, content_id) VALUES (?,?,?)";
	      $db->Execute($query, array($new_addt_id, $oneeditor, $this->Id()));
	    }
	}

      if( is_array($this->_props) && count($this->_props) )
	{
	  // :TODO: There might be some error checking there
	  $this->_save_properties();
	}
      else
	{
	  if (true == $config["debug"])
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>Error updating : the content has no properties</p>\n";
	    }
	}

      cms_route_manager::del_static('','__CONTENT__',$this->mId);
      if( $this->mURL != '' )
	{
	  $route = CmsRoute::new_builder($this->mURL,'__CONTENT__',$this->mId,null,TRUE);;
	  cms_route_manager::add_static($route);
	}
    }

    /**
     * Insert the content in the db
     *
     * @todo this function should return something
     */
    # :TODO: This function should return something
    # :TODO: Take care bout hierarchy here, it has no value !
    # :TODO: Figure out proper item_order
    protected function Insert()
    {
      $gCms = cmsms();
      global $debug_errors;
      $db = $gCms->GetDb();
      $config = $gCms->GetConfig();

      $result = false;

#Figure out the item_order
      if ($this->mItemOrder < 1)
	{
	  $query = "SELECT max(item_order) as new_order FROM ".cms_db_prefix()."content WHERE parent_id = ?";
	  $row = $db->Getrow($query, array($this->mParentId));

	  if ($row)
	    {
	      if ($row['new_order'] < 1)
		{
		  $this->mItemOrder = 1;
		}
	      else
		{
		  $this->mItemOrder = $row['new_order'] + 1;
		}
	    }
	}

      $newid = $db->GenID(cms_db_prefix()."content_seq");
      $this->mId = $newid;

      $this->mModifiedDate = $this->mCreationDate = trim($db->DBTimeStamp(time()), "'");

      $query = "INSERT INTO ".$config["db_prefix"]."content (content_id, content_name, content_alias, type, owner_id, parent_id, template_id, item_order, hierarchy, id_hierarchy, active, default_content, show_in_menu, cachable, secure, page_url, menu_text, markup, metadata, titleattribute, accesskey, tabindex, last_modified_by, create_date, modified_date) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

      $dbresult = $db->Execute($query, array(
					     $newid,
					     $this->mName,
					     $this->mAlias,
					     strtolower($this->mType),
					     $this->mOwner,
					     $this->mParentId,
					     $this->mTemplateId,
					     $this->mItemOrder,
					     $this->mHierarchy,
					     $this->mIdHierarchy,
					     ($this->mActive == true         ? 1 : 0),
					     ($this->mDefaultContent == true ? 1 : 0),
					     ($this->mShowInMenu == true     ? 1 : 0),
					     ($this->mCachable == true       ? 1 : 0),
					     $this->mSecure,
					     $this->mURL,
					     $this->mMenuText,
					     $this->mMarkup,
					     $this->mMetadata,
					     $this->mTitleAttribute,
					     $this->mAccessKey,
					     $this->mTabIndex,
					     $this->mLastModifiedBy,
					     $this->mModifiedDate,
					     $this->mCreationDate
					     ));

      if (! $dbresult)
	{
	  die($db->sql.'<br/>'.$db->ErrorMsg());
	  if ($config["debug"] == true)
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>Error inserting content</p>\n";
	    }
	}

      if (is_array($this->_props) && count($this->_props))
	{
	  // :TODO: There might be some error checking there
	  debug_buffer('save from ' . __LINE__);
	  $this->_save_properties();
	}
      else
	{
	  if (true == $config["debug"])
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>Error inserting : the content has no properties</p>\n";
	    }
	}
      if (isset($this->mAdditionalEditors))
	{
	  foreach ($this->mAdditionalEditors as $oneeditor)
	    {
	      $new_addt_id = $db->GenID(cms_db_prefix()."additional_users_seq");
	      $query = "INSERT INTO ".cms_db_prefix()."additional_users (additional_users_id, user_id, content_id) VALUES (?,?,?)";
	      $db->Execute($query, array($new_addt_id, $oneeditor, $this->Id()));
	    }
	}

      if( $this->mURL != '' )
	{
	  $route = CmsRoute::new_builder($this->mURL,'__CONTENT__',$this->mId,'',TRUE);
	  cms_route_manager::add_static($route);
	}
    }

    /**
     * Test if the array given contains valid data for the object
     * This function is used to check that no compulsory argument
     * has been forgotten by the user
     *
     * We do not check the Id because there can be no Id (new content)
     * That's up to Save to check this.
     *
     * @returns	FALSE if data is ok, and an array of invalid parameters else
     */
    public function ValidateData()
    {
      $errors = array();

      if ($this->mParentId < -1) {
	$errors[] = lang('invalidparent');
	$result = false;
      }
	  
      if ($this->mName == '') {
	if ($this->mMenuText != '') {
	  $this->mName = $this->mMenuText;
	}
	else {
	  $errors[]= lang('nofieldgiven',array(lang('title')));
	  $result = false;
	}
      }
	  
      if ($this->mMenuText == '') {
	if ($this->mName != '') {
	  $this->mMenuText = $this->mName;
	}
	else {
	  $errors[]=lang('nofieldgiven',array(lang('menutext')));
	  $result = false;
	}
      }
		
      if (!$this->HandlesAlias()) {
	if ($this->mAlias != $this->mOldAlias || ($this->mAlias == '' && $this->RequiresAlias()) ) {
	  $gCms = cmsms();
	  $contentops = $gCms->GetContentOperations();
	  $error = $contentops->CheckAliasError($this->mAlias, $this->mId);
	  if ($error !== FALSE) {
	    $errors[]= $error;
	    $result = false;
	  }
	}
      }

      $auto_type = content_assistant::auto_create_url();
      if( $this->mURL == '' && get_site_preference('content_autocreate_urls') ) {
	// create a valid url.
	if( !$this->DefaultContent() ) {
	  if( get_site_preference('content_autocreate_flaturls',0) ) {
	    // the default url is the alias... but not synced to the alias.
	    $this->mURL = $this->mAlias;
	  }
	  else {
	    // if it don't explicitly say 'flat' we're creating a hierarchical url.
	    $gCms = cmsms();
	    $tree = $gCms->GetHierarchyManager();
	    $node = $tree->find_by_tag('id',$this->ParentId());
	    $stack = array($this->mAlias);
	    $parent_url = '';
	    $count = 0;
	    while( $node ) {
	      $tmp_content = $node->GetContent();
	      if( $tmp_content ) {
		$tmp = $tmp_content->URL();
		if( $tmp != '' && $count == 0 ) {
		  // try to build the url out of the parent url.
		  $parent_url = $tmp;
		  break;
		}
		array_unshift($stack,$tmp_content->Alias());
	      }
	      $node = $node->GetParent();
	      $count++;
	    }

	    if( $parent_url != '' ) {
	      // woot, we got a prent url.
	      $this->mURL = $parent_url.'/'.$this->mAlias;
	    }
	    else {
	      $this->mURL = implode('/',$stack);
	    }
	  }
	}
      }
      if( $this->mURL == '' && 
	  get_site_preference('content_mandatory_urls') && 
	  !$this->mDefaultContent &&
	  $this->HasUsableLink() ) {
	// page url is empty and mandatory
	$errors[] = lang('content_mandatory_urls');
      }
      else if( $this->mURL != '' ) {
	// page url is not empty, check for validity.
	$this->mURL = strtolower(trim($this->mURL," /\t\r\n\0\x08")); // silently delete bad chars. and convert to lowercase.
	if( $this->mURL != '' && !content_assistant::is_valid_url($this->mURL,$this->mId) ) {
	  // and validate the URL.
	  $errors[] = lang('invalid_url2');
	}
      }

      return (count($errors) > 0?$errors:FALSE);
    }

    /**
     * Delete the current content object from the database.
     *
     * @todo this function should return something, or throw an exception
     */
    function Delete()
    {
      $gCms = cmsms();
      global $debug_errors;
      $config = $gCms->GetConfig();
      Events::SendEvent('Core', 'ContentDeletePre', array('content' => &$this));
      $db = $gCms->GetDb();
      $result = false;

      if (-1 > $this->mId)
	{
	  if (true == $config["debug"])
	    {
	      # :TODO: Translate the error message
	      $debug_errors .= "<p>Could not delete content : invalid Id</p>\n";
	    }
	}
      else
	{
	  $query = "DELETE FROM ".cms_db_prefix()."content WHERE content_id = ?";
	  $dbresult = $db->Execute($query, array($this->mId));

	  if (! $dbresult)
	    {
	      if (true == $config["debug"])
		{
		  # :TODO: Translate the error message
		  $debug_errors .= "<p>Error deleting content</p>\n";
		}
	    }

	  // Fix the item_order if necessary
	  $query = "UPDATE ".cms_db_prefix()."content SET item_order = item_order - 1 WHERE parent_id = ? AND item_order > ?";
	  $result = $db->Execute($query,array($this->ParentId(),$this->ItemOrder()));

	  $cachefilename = TMP_CACHE_LOCATION . '/contentcache.php';
	  @unlink($cachefilename);

	  // DELETE properties
	  $query = 'DELETE FROM '.cms_db_prefix().'content_props WHERE content_id = ?';
	  $result = $db->Execute($query,array($this->mId));
	  $this->_props = null;

	  // Delete additional editors.
	  $query = 'DELETE FROM '.cms_db_prefix().'additional_users WHERE content_id = ?';
	  $result = $db->Execute($query,array($this->mId));
	  $this->mAdditionalEditors = null;

	  // Delete route
	  if( $this->mURL != '' )
	    {
	      cms_route_manager::del_static($this->mURL);
	    }
	}

      Events::SendEvent('Core', 'ContentDeletePost', array('content' => &$this));
    }

    /**
     * Function for the subclass to parse out data for it's parameters (usually from $_POST)
     * This method is typically called from an editor form to allow modifying the content object from 
     * form input fields.
     *
     * @abstract
     * @return void
     */
    public function FillParams($params,$editing = false)
    {
      // content property parameters
      $parameters = array('extra1','extra2','extra3','image','thumbnail');
      foreach ($parameters as $oneparam)
	{
	  if (isset($params[$oneparam]))
	    {
	      $this->SetPropertyValue($oneparam, $params[$oneparam]);
	    }
	}

      // go through the list of base parameters
      // setting them from params
      
      // title
      if (isset($params['title']))
	{
	  $this->mName = $params['title'];
	}

      // menu text
      if (isset($params['menutext']))
	{
	  $this->mMenuText = $params['menutext'];
	}

      // parent id
      if( isset($params['parent_id']) )
	{
	  if ($this->mParentId != $params['parent_id'])
	    {
	      $this->mHierarchy = '';
	      $this->mItemOrder = -1;
	    }
	  $this->mParentId = $params['parent_id'];
	}

      // active
      if (isset($params['active']))
	{
	  $this->mActive = $params['active'];
	  if( $this->DefaultContent() )
	    {
	      $this->mActive = 1;
	    }
	}
      
      // show in menu
      if (isset($params['showinmenu']))
	{
	  $this->mShowInMenu = $params['showinmenu'];
	}

      // alias
      $tmp = '';
      if( isset($params['alias']) )
	{
	  $tmp = trim($params['alias']);
	}
      if( !$editing || isset($params['alias']) )
	{
	  // the alias param may not exist (depending upon permissions)
	  // this method will set the alias to the supplied value if it is set
	  // or auto-generate one, when adding a new page.
	  $this->SetAlias($tmp);
	}

      // target
      if (isset($params['target']))
	{
	  $val = $params['target'];
	  if( $val == '---' )
	    {
	      $val = '';
	    }
	  $this->SetPropertyValue('target', $val);
	} 

      // title attribute
      if (isset($params['titleattribute']))
	{
	  $this->mTitleAttribute = $params['titleattribute'];
	}

      // accesskey
      if (isset($params['accesskey']))
	{
	  $this->mAccessKey = $params['accesskey'];
	}

      // tab index
      if (isset($params['tabindex']))
	{
	  $this->mTabIndex = $params['tabindex'];
	}

      // cachable
      if (isset($params['cachable']))
	{
	  $this->mCachable = $params['cachable'];
	}
      else
	{
	  $this->_handleRemovedBaseProperty('cachable','mCachable');
	}

      // secure
      if (isset($params['secure']))
	{
	  $this->mSecure = $params['secure'];
	}
      else
	{
	  $this->_handleRemovedBaseProperty('secure','mSecure');
	}

      // url
      if (isset($params['page_url']))
	{
	  $this->mURL = $params['page_url'];
	}
      else
	{
	  $this->_handleRemovedBaseProperty('page_url','mURL');
	}

      // owner
      if (isset($params["ownerid"]))
	{
	  $this->SetOwner($params["ownerid"]);
	}
	 
      // additional editors
      if (isset($params["additional_editors"]))
	{
	  $addtarray = array();
	  if( is_array($params['additional_editors']) )
	    {
	      foreach ($params["additional_editors"] as $addt_user_id)
		{
		  $addtarray[] = $addt_user_id;
		}
	    }
	  $this->SetAdditionalEditors($addtarray);
	}
    }

    /**
     * A function to get the internally generated URL for this content type.
     * This method may be overridden by content types.
     *
     * @param boolean if true, and mod_rewrite is enabled, build a URL suitable for mod_rewrite.
     * @return string
     */
    public function GetURL($rewrite = true)
    {
      $gCms = cmsms();
      $config = $gCms->GetConfig();
      $url = "";
      $alias = ($this->mAlias != ''?$this->mAlias:$this->mId);

      $base_url = $config['root_url'];
      if( $this->Secure() )
	{
	  if( isset($config['ssl_url']) )
	    {
	      $base_url = $config['ssl_url'];
	    }
	  else
	    {
	      $base_url = str_replace('http://','https://',$base_url);
	    }
	}

      /* use root_url for default content */
      if($this->mDefaultContent) {
	$url =  $base_url . '/';
	return $url;
      }

      if ($config["url_rewriting"] == 'mod_rewrite' && $rewrite == true)
	{
	  $str = $this->HierarchyPath();
	  if( $this->mURL != '')
	    {
	      // we have a url path
	      $str = $this->mURL;
	    }
	  $url = $base_url. '/' . $str . (isset($config['page_extension'])?$config['page_extension']:'.html');
	}
      else if (isset($_SERVER['PHP_SELF']) && $config['url_rewriting'] == 'internal' && $rewrite == true)
	{
	  $str = $this->HierarchyPath();
	  if( $this->mURL != '')
	    {
	      // we have a url path
	      $str = $this->mURL;
	    }
	  $url = $base_url . '/index.php/' . $str . (isset($config['page_extension'])?$config['page_extension']:'.html');
	}
      else
	{
	  $url = $base_url . '/index.php?' . $config['query_var'] . '=' . $alias;
	}
      return $url;
    }


    /**
     * Show the content
     *
     * @abstract
     * @param string An optional property name to display.
     */
    public function Show($param = '')
    {
    }
	
    /**
     * Used from a page that allows content editing. This method the list of distinct sections
     * that devides up the various logical sections that this content type supports for editing.
     *
     * @abstract
     * @return array List of tab name strings.
     */
    public function TabNames()
    {
        return array();
    }

    /** 
     * Used from within a page that allows editing content this method returns the input fields for
     * the various fields that can be edited.
     *
     * @abstract
     * @param boolean Wether we are adding a new content page, or editing an existing content page.
     * @param int     The tab index.
     * @param boolean unused??
     */
    public function EditAsArray($adding = false, $tab = 0, $showadmin = false)
    {
	# :TODO:
	return array(array('Error','Edit Not Defined!'));
    }


    /**
     * Show Help
# disabled to see if its used.
    public function Help()
    {
    	# :TODO:
    	return "<tr><td>Help Not Defined</td></tr>";
    }
     */

    /**
     * Method to indicate wether the current page has children.
     *
     * @param boolean should we test only for active children.
     * @return booelan
     */
    public function HasChildren($activeonly = false)
    {
      $hm = cmsms()->GetHierarchyManager();
      $node = $hm->getNodeById($this->mId);
      if( !$node->has_children() ) return false;
      if( $activeonly == false) return true;

      $children = $node->get_children();
      if( $children )
	{
	  for( $i = 0; $i < count($children); $i++ )
	    {
	      $content = $children[$i]->getContent();
	      if( $content->Active() ) return true;
	    }
	}

      return false;
    }

    /**
     * Return a list of additional editors
     * Note: in the returned array, group id's are specified as negative integers.
     *
     * @return mixed  Array of uids and group ids, or null
     */
    public function GetAdditionalEditors()
    {
      if (!isset($this->mAdditionalEditors))
	{
	  $gCms = cmsms();
	  $db = $gCms->GetDb();

	  $this->mAdditionalEditors = array();

	  $query = "SELECT user_id FROM ".cms_db_prefix()."additional_users WHERE content_id = ?";
	  $dbresult = $db->Execute($query,array($this->mId));

	  while ($dbresult && !$dbresult->EOF)
	    {
	      $this->mAdditionalEditors[] = $dbresult->fields['user_id'];
	      $dbresult->MoveNext();
	    }

	  if ($dbresult) $dbresult->Close();
	}
      return $this->mAdditionalEditors;
    }

    /**
     * Set the list of additional editors
     * Note: in the provided array, group id's are specified as negative integers.
     *
     * @param mixed  Array of uids and group ids, or null
     */
    public function SetAdditionalEditors($editorarray)
    {
      $this->mAdditionalEditors = $editorarray;
    }

    static public function GetAdditionalEditorInput($addteditors,$owner_id = -1)
    {
      $ret[] = lang('additionaleditors');
      $text = '<input name="additional_editors" type="hidden" value=""/>';
      $text .= '<select name="additional_editors[]" multiple="multiple" size="5">';

      $gCms = cmsms();
      $userops = $gCms->GetUserOperations();
      $groupops = $gCms->GetGroupOperations();
      $allusers = $userops->LoadUsers();
      $allgroups = $groupops->LoadGroups();
      foreach ($allgroups as $onegroup)
	{
	  if( $onegroup->id == 1 ) continue;
	  $val = $onegroup->id*-1;
	  $text .= '<option value="'.$val.'"';
	  if( in_array($val,$addteditors) )
	    {
	      $text .= ' selected="selected"';
	    }
	  $text .= '>'.lang('group').': '.$onegroup->name."</option>";
		   
	}

      foreach ($allusers as $oneuser)
	{
	  if ($oneuser->id != $owner_id && $oneuser->id != 1)
	    {
	      $text .= '<option value="'.$oneuser->id.'"';
	      if (in_array($oneuser->id, $addteditors))
		{
		  $text .= ' selected="selected"';
		}
	      $text .= '>'.$oneuser->username.'</option>';
	    }
	}

      $text .= '</select>';
      $ret[] = $text;
      return $ret;
    }


    /**
     * Provides an input element to display the list of additional editors.
     * This method is usually called from within this object.
     *
     * @param mixed An optional array of additional editor id's (group ids specified with negative values)
     * @return string The input element.
     */
    public function ShowAdditionalEditors($addteditors = '')
    {
      $ret = array();
      if( $addteditors == '' )
	{
	  $addteditors = $this->GetAdditionalEditors();
	}
      return self::GetAdditionalEditorInput($addteditors,$this->Owner());
    }

    /**
     * Indicates wether this content type can be the default page for a CMSMS website
     *
     * @abstract
     * @returns boolean
     */
    public function IsDefaultPossible()
    {
      return FALSE;
    }

    /**
     * Set a flag indicating that we are adding a new content object and not editing an existing one
     * This is usually called from a script that provides the ability to add content objects.
     */
    public function SetAddMode($flag = true)
    {
      $this->_add_mode = $flag;
    }

    /* private */
    private function _handleRemovedBaseProperty($name,$member)
    {
      if( !is_array($this->_attributes) ) return FALSE;
      if( !in_array($name,$this->_attributes) )
	{
	  if( isset($this->_prop_defaults[$name]) )
	    {
	      $this->$member = $this->_prop_defaults[$name];
	      return TRUE;
	    }
	}
      return FALSE;
    }

    /**
     * @deprecated 
     */
    public function AddExtraProperty($name,$type = 'string')
    {
      return; // debug
    }

    /**
     * Remove a property from the known property list.
     * Specify a default value to use if the property is called.
     *
     * @param string The property name
     * @param string The default value.
     */
    protected function RemoveProperty($name,$dflt)
    {
      if( !is_array($this->_attributes) ) return;
      $tmp = array();
      for( $i = 0; $i < count($this->_attributes); $i++ )
	{
	  if( is_array($this->_attributes[$i]) && $this->_attributes[$i][0] == $name )
	    {
	      continue;
	    }
	  $tmp[] = $this->_attributes[$i];
	}
      $this->_attributes = $tmp;
      $this->_prop_defaults[$name] = $dflt;
    }

    /*
     * Add a property that is directly associtated with a field in the content table.
     *
     * @param string The property name
     * @param integer The priority
     * @param boolean Whether this field is required for this content type
     * @param string  (optional) unused.
     */
    protected function AddBaseProperty($name,$priority,$is_required = 0,$type = 'string')
    {
      if( !is_array($this->_attributes) )
	{
	  $this->_attributes = array();
	}

      $this->_attributes[] = array($name,$priority,$is_required);
    }

    /*
     * Alias for AddBaseProperty
     */
    protected function AddContentProperty($name,$priority,$is_required = 0,$type = 'string')
    {
      return $this->AddBaseProperty($name,$priority,$is_required,$type);
    }


    /*
     * Given a string, see if it's a known property name.
     *
     * @param string The property name
     * @return boolean
     */
    protected function is_known_property($str)
    {
      $tmp = array();
      foreach( $this->_attributes as $one )
	{
	  $tmp[] = $one[0];
	}
	  
      return in_array($str,$tmp);
    }

    /*
     * Given the list of registered properties, cross reference with our
     * basic attributes list, and figure out which ones should be displayed
     *
     * @return array of input elements of attributes that can be edited for this form.
     */
    protected function display_attributes($adding,$negative = 0)
    {
      // get our required attributes
      $basic_attributes = array();
      foreach( $this->_attributes as $one )
	{
	  if( $one[2] == 1 ) $basic_attributes[] = $one;
	}

      // merge in preferred basic attributes
      $tmp = get_site_preference('basic_attributes');
      if( !empty($tmp) )
	{
	  $tmp = explode(',',$tmp);
	  foreach( $tmp as $basic )
	    {
	      $found = NULL;
	      foreach( $this->_attributes as $one )
		{
		  if( $one[0] == $basic ) {
		    $found = $one;
		    break;
		  }
		}
	      if( $found )
		{
		  $basic_attributes[] = $found;
		}
	    }
	}

      $attrs = $basic_attributes;
      if( $negative )
	{
	  // build a new list of all properties... except those in the basic_attributes
	  $attrs = array();
	  foreach( $this->_attributes as $one )
	    {
	      $found = 0;
	      foreach( $basic_attributes as $basic )
		{
		  if( $basic[0] == $one[0] )
		    {
		      $found = 1;
		    }
		}

	      if( !$found )
		{
		  $attrs[] = $one;
		}
	    }
	}

      // remove any duplicates
      $tmp = array();
      foreach( $attrs as $one )
	{
	  $found = 0;
	  foreach( $tmp as $t1 )
	    {
	      if( $one[0] == $t1[0] )
		{
		  $found = 1;
		  break;
		}
	    }
	  if( !$found )
	    {
	      $tmp[] = $one;
	    }
	}
      $attrs = $tmp;

      // sort the attributes on the 2nd element...
      $fn = create_function('$a,$b','if( $a[1] < $b[1] ) return -1; else if( $a[1] == $b[1] ) return 0; else return $b;');
      usort($attrs,$fn);

      $tmp = $this->display_admin_attributes($attrs,$adding);
      return $tmp;
    }

    /* private */
    private function display_admin_attributes($attributelist,$adding)
    {
      // sort the attributes

      $ret = array();
      foreach( $attributelist as $one )
	{
	  $tmp = $this->display_single_element($one[0],$adding);
	  if( is_array($tmp) )
	    {
	      $ret[] = $tmp;
	    }
	}
      return $ret;
    }

    /**
     * A method to display a single input element for an object basic, or extended property.
     *
     * @abstract
     * @param string The property name
     * @param boolean Wether or not we are in add or edit mode.
     * @return array consisting of two elements.  A label, and the input element.
     */
    protected function display_single_element($one,$adding)
    {
      $gCms = cmsms();
      $config = $gCms->GetConfig();

      switch( $one )
	{
	case 'cachable':
	  return array('<label for="in_cachable">'.lang('cachable').':</label>',
		       '<input type="hidden" name="cachable" value="0"/><input id="in_cachable" class="pagecheckbox" type="checkbox" value="1" name="cachable"'.($this->mCachable?' checked="checked"':'').' />',lang('help_page_cachable'));
	  break;
	
	case 'title':
	  {
	    return array('<label for="in_title">*'.lang('title').'</label>:','<input type="text" id="in_title" name="title" value="'.cms_htmlentities($this->mName).'" />');
	  }
	  break;
	      
	case 'menutext':
	  {
	    return array('<label for="in_menutext">*'.lang('menutext').'</label>:','<input type="text" name="menutext" id="in_menutext" value="'.cms_htmlentities($this->mMenuText).'" />');
	  }
	  break;
	      
	case 'parent':
	  {
	    $contentops = $gCms->GetContentOperations();
	    $tmp = $contentops->CreateHierarchyDropdown($this->mId, $this->mParentId, 'parent_id', 0, 1, 0, 1,get_site_preference('listcontent_showtitle',true) );
	    if( empty($tmp) && !check_permission(get_userid(),'Manage All Content') )
	      return array('','<input type="hidden" name="parent_id" value="'.$this->mParentId.'" />');
	    if( !empty($tmp) ) return array('<label for="parent_id">'.lang('parent').'</label>:',$tmp);
	  }
	  break;

	case 'active':
	  if( !$this->DefaultContent() )
	    {
	      return array('<label for="id_active">'.lang('active').'</label>:','<input type="hidden" name="active" value="0"/><input class="pagecheckbox" type="checkbox" name="active" id="id_active" value="1"'.($this->mActive?' checked="checked"':'').' />');
	    }
	  break;
	      
	case 'showinmenu':
	  return array('<label for="showinmenu">'.lang('showinmenu').'</label>:','<input type="hidden" name="showinmenu" value="0"/><input class="pagecheckbox" type="checkbox" value="1" name="showinmenu" id="showinmenu"'.($this->mShowInMenu?' checked="checked"':'').' />');
	  break;
	      
	case 'target':
	  {
	    $text = '<option value="---">'.lang('none').'</option>';
	    $text .= '<option value="_blank"'.($this->GetPropertyValue('target')=='_blank'?' selected="selected"':'').'>_blank</option>';
	    $text .= '<option value="_parent"'.($this->GetPropertyValue('target')=='_parent'?' selected="selected"':'').'>_parent</option>';
	    $text .= '<option value="_self"'.($this->GetPropertyValue('target')=='_self'?' selected="selected"':'').'>_self</option>';
	    $text .= '<option value="_top"'.($this->GetPropertyValue('target')=='_top'?' selected="selected"':'').'>_top</option>';
	    return array('<label for="target">'.lang('target').'</label>:','<select name="target" id="target">'.$text.'</select>',
			 lang('info_target'));
		
	  }
	  break;
	      
	case 'alias':
	  return array('<label for="alias">'.lang('pagealias').'</label>:','<input type="text" name="alias" id="alias" value="'.$this->mAlias.'" />',lang('help_page_alias'));
	  break;
	      
	case 'secure':
	  {
	    $opt = '';
	    if( $this->mSecure )
	      {
		$opt = ' checked="checked"';
	      }
	    $str  = '<input type="hidden" name="secure" value="0"/>';
	    $str .= '<input type="checkbox" name="secure" id="secure" value="1"'.$opt.'/>';
	    return array('<label for="secure">'.lang('secure_page').'</label>:',$str);
	  }
	  break;

	case 'page_url':
	  if( !$this->DefaultContent() )
	    {
	      $str = '<input type="text" name="page_url" id="page_url" value="'.$this->mURL.'" size="50" maxlength="255"/>';
	      $prompt = '<label for="page_url">'.lang('page_url').'</label>:';
	      if( get_site_preference('content_mandatory_urls',0) )
		{
		  $prompt = '*'.$prompt;
		}
	      return array($prompt,$str,lang('help_page_url'));
	    }
	  break;

	case 'image':
	  {
	    $dir = cms_join_path($config['image_uploads_path'],get_site_preference('content_imagefield_path'));
	    $data = $this->GetPropertyValue('image');
	    $dropdown = create_file_dropdown('image',$dir,$data,'jpg,jpeg,png,gif','',true,'','thumb_',1,1);
	    if( !$dropdown ) return;
	    return array('<label for="image">'.lang('image').'</label>:',$dropdown);
	  }
	  break;
	      
	case 'thumbnail':
	  {
	    $dir = cms_join_path($config['image_uploads_path'],get_site_preference('content_thumbnailfield_path'));
	    $data = $this->GetPropertyValue('thumbnail');
	    $dropdown = create_file_dropdown('thumbnail',$dir,$data,'jpg,jpeg,png,gif','',true,'','thumb_',0,1);
	    if( !$dropdown ) return FALSE;
	    return array('<label for="thumbnail">'.lang('thumbnail').'</label>:',$dropdown);
	  }
	  break;
	      
	case 'titleattribute':
	  {
	    return array('<label for="titleattribute">'.lang('titleattribute').'</label>:','<input type="text" name="titleattribute" id="titleattribute" maxlength="255" size="80" value="'.cms_htmlentities($this->mTitleAttribute).'" />');
	  }
	  break;
	      
	case 'accesskey':
	  {
	    return array('<label for="accesskey">'.lang('accesskey').'</label>:','<input type="text" name="accesskey" id="accesskey" maxlength="5" value="'.cms_htmlentities($this->mAccessKey).'" />');
	  }
	  break;

	case 'tabindex':
	  {
	    return array('<label for="tabindex">'.lang('tabindex').'</label>:','<input type="text" name="tabindex" id="tabindex" maxlength="5" value="'.cms_htmlentities($this->mTabIndex).'" />');
	  }
	  break;
	      
	case 'extra1':
	  {
	    return array('<label for="extra1">'.lang('extra1').'</label>:','<input type="text" name="extra1" id="extra1" maxlength="255" size="80" value="'.cms_htmlentities($this->GetPropertyValue('extra1')).'" />');
	  }
	  break;
	      
	case 'extra2':
	  {
	    return array('<label for="extra2">'.lang('extra2').'</label>:','<input type="text" name="extra2" id="extra2" maxlength="255" size="80" value="'.cms_htmlentities($this->GetPropertyValue('extra2')).'" />');
	  }
	  break;
	      
	case 'extra3':
	  {
	    return array('<label for="extra3">'.lang('extra3').'</label>:','<input type="text" name="extra3" id="extra3" maxlength="255" size="80" value="'.cms_htmlentities($this->GetPropertyValue('extra3')).'" />');
	  }
	  break;

	case 'owner':
	  {
	    $showadmin = check_ownership(get_userid(), $this->Id());
	    $userops = $gCms->GetUserOperations();
	    if (!$adding && ($showadmin || check_permission(get_userid(),'Manage All Content')) )
	      {
		return array('<label for="owner">'.lang('owner').'</label>:', $userops->GenerateDropdown($this->Owner()));
	      }
	  }
	  break;

	case 'additionaleditors':
	  {
	    // do owner/additional-editor stuff
	    if( $adding || check_ownership(get_userid(),$this->Id()) || check_permission(get_userid(),'Manage All Content'))
	      {
		return $this->ShowAdditionalEditors();
	      }
	  }
	  break;

	default:
	  stack_trace();
	  die('unknown property '.$one);
	}
    }

    protected function SetError($str)
    {
      // we don't need this being serialized.
      cms_utils::set_app_data('content_error',$str);
    }

    public function GetError()
    {
      $str = cms_utils::get_app_data('content_error');
      return $str;
    }
}
?>

File Manager Version 1.0, Coded By Lucas
Email: hehe@yahoo.com