[limb-svn] r6240 - in 3.x/examples: . cms cms/build cms/cli cms/settings cms/src cms/src/captcha cms/src/controller cms/src/model cms/src/validation cms/www

svn at limb-project.com svn at limb-project.com
Tue Aug 28 18:21:06 MSD 2007


Author: serega
Date: 2007-08-28 18:21:06 +0400 (Tue, 28 Aug 2007)
New Revision: 6240
URL: http://fisheye.limb-project.com/changelog/limb/?cs=6240

Added:
   3.x/examples/cms/
   3.x/examples/cms/CHANGELOG
   3.x/examples/cms/INSTALL
   3.x/examples/cms/VERSION
   3.x/examples/cms/build/
   3.x/examples/cms/build/build_release.php
   3.x/examples/cms/cli/
   3.x/examples/cms/cli/cron.php
   3.x/examples/cms/cli/db_dump.php
   3.x/examples/cms/cli/db_load.php
   3.x/examples/cms/common.inc.php
   3.x/examples/cms/init/
   3.x/examples/cms/settings/
   3.x/examples/cms/settings/db.conf.php
   3.x/examples/cms/settings/navigation.conf.php
   3.x/examples/cms/settings/wact.conf.php
   3.x/examples/cms/setup.override.php-example
   3.x/examples/cms/setup.php
   3.x/examples/cms/src/
   3.x/examples/cms/src/captcha/
   3.x/examples/cms/src/captcha/Captcha.class.php
   3.x/examples/cms/src/captcha/php-captcha.inc.php
   3.x/examples/cms/src/controller/
   3.x/examples/cms/src/controller/AdminCatalogCategoryController.class.php
   3.x/examples/cms/src/controller/AdminCatalogItemController.class.php
   3.x/examples/cms/src/controller/AdminFeedbackMessageController.class.php
   3.x/examples/cms/src/controller/AdminNewsController.class.php
   3.x/examples/cms/src/controller/AdminPollController.class.php
   3.x/examples/cms/src/controller/CatalogController.class.php
   3.x/examples/cms/src/controller/CatalogItemController.class.php
   3.x/examples/cms/src/controller/FeedbackController.class.php
   3.x/examples/cms/src/controller/NewsController.class.php
   3.x/examples/cms/src/controller/PollController.class.php
   3.x/examples/cms/src/model/
   3.x/examples/cms/src/model/CatalogCategory.class.php
   3.x/examples/cms/src/model/CatalogItem.class.php
   3.x/examples/cms/src/model/FeedbackMessage.class.php
   3.x/examples/cms/src/model/News.class.php
   3.x/examples/cms/src/model/Poll.class.php
   3.x/examples/cms/src/model/PollAnswer.class.php
   3.x/examples/cms/src/validation/
   3.x/examples/cms/src/validation/CaptchaRule.class.php
   3.x/examples/cms/template/
   3.x/examples/cms/toolkit.inc.php
   3.x/examples/cms/www/
   3.x/examples/cms/www/.htaccess
   3.x/examples/cms/www/favicon.ico
   3.x/examples/cms/www/index.php
Log:
-- initial commit of new example application build with Limb3 CMS package. The example is not runnable yet.

Added: 3.x/examples/cms/CHANGELOG
===================================================================
--- 3.x/examples/cms/CHANGELOG	                        (rev 0)
+++ 3.x/examples/cms/CHANGELOG	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,3 @@
+0.1.0-alpha - 19 July 2007
+==================================================
+-- Initial release of simple application build with Limb3 CMS package

Added: 3.x/examples/cms/INSTALL
===================================================================
--- 3.x/examples/cms/INSTALL	                        (rev 0)
+++ 3.x/examples/cms/INSTALL	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,61 @@
+=========== CMS - simple example of Limb3 based application build with CMS package ===========
+
+CMS example include:
+1) Admin control panel
+2) User authentication
+4) Basic cms functionality like news, guestbook, regular text pages etc.
+
+To install cms example on your PC:
+
+1) Unpack the archive in some directory that can be reached by your web-server, for example in /var/www/cms.
+   (here we're assuming that /var/www directory can be accessed by your web-server as http://localhost)
+
+2) Make /var/www/cms/var directory writable for the web server:
+
+$ chmod 777 /var/www/cms/var
+
+3) Configuring application database.
+
+  Using SQLite database
+  ------------------------------
+  CMS example application uses SQLite database by default. Make sure:
+  a) You have enabled SQLite support in php.ini.
+  b) Database itself and database directory are writable for web server:
+  $ chmod 666 -R /var/www/cms/db
+
+  Using MySQL database
+  ------------------------------
+  If you want to use MySQL as database then you need to create some database on MySQL server, e.g. "limb_cms".
+
+  Fill this database with a dump file shipped with CMS application in init directory, e.g.:
+
+  $mysql -u user -p secret shop < /var/www/cms/init/db.mysql
+
+  To configure database settings for application you need to change /var/www/cms/settings/db.conf.php file , e.g.:
+
+  <?php
+  $conf = array('dsn' => 'mysql://user:secret@localhost/limb_cms?charset=utf8');
+  ?>
+
+That is all.
+
+Type in your favourite browser - http://localhost/cms/www
+
+But you can also setup virtual host for this CMS example application:
+
+1) Create shop VirtualHost in Apache config file(httpd.conf), something like this:
+
+<VirtualHost *>
+    DocumentRoot /var/www/cms/www/
+    ServerName cms
+    ErrorLog logs/shop-error_log
+    CustomLog logs/shop-access_log common
+</VirtualHost>
+
+2) Put "cms" host name into /etc/hosts file(%WINDOWS%/system32/drivers/etc/hosts under Windows):
+
+127.0.0.1  cms
+
+3) Restart Apache
+
+4) Open http://cms/ in your browser

Added: 3.x/examples/cms/VERSION
===================================================================
--- 3.x/examples/cms/VERSION	                        (rev 0)
+++ 3.x/examples/cms/VERSION	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1 @@
+cms-0.1.0-alpha

Added: 3.x/examples/cms/build/build_release.php
===================================================================
--- 3.x/examples/cms/build/build_release.php	                        (rev 0)
+++ 3.x/examples/cms/build/build_release.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,96 @@
+<?php
+//Builds project release.
+
+$RELEASE_NAME = "limb3-cms-0.1.0";
+$RELEASE_DIR = "./release/";
+$WORKING_COPY_DIR = dirname(__FILE__) . "/../";
+
+$RSYNC = "rsync";
+$SVN = "svn";
+$TAR = "$RELEASE_NAME.tar.gz";
+$FULL_RELEASE_PATH = $RELEASE_DIR . $RELEASE_NAME;
+
+//==================!!! don't edit below if not sure !!!==================
+
+function cleanup()
+{
+  global $RELEASE_DIR;
+
+  echo "Cleaning $RELEASE_DIR...\n";
+
+  exec("rm -Rf $RELEASE_DIR", $out, $ret);
+
+  if($ret != 0)
+  {
+    echo "...\nfailure\n";
+    exit(1);
+  }
+
+  mkdir($RELEASE_DIR);
+}
+
+function export_project()
+{
+  global $WORKING_COPY_DIR;
+  global $FULL_RELEASE_PATH;
+  global $RSYNC;
+
+  echo "Exporting project...\n";
+
+  //exec("$SVN export $WORKING_COPY_DIR $FULL_RELEASE_PATH");
+  exec("$RSYNC -a --exclude=var --exclude=.svn " . cygwin_path($WORKING_COPY_DIR) . " " . cygwin_path($FULL_RELEASE_PATH));
+}
+
+function cygwin_path($path)
+{
+  $path = str_replace('\\', '/', $path);
+  $path = str_replace('//', '/', $path);
+
+  if(DIRECTORY_SEPARATOR == '\\')//is win32
+    return preg_replace('~^(\w+):~', '/cygdrive/$1', preg_replace('~\\\\+~', '/', strtolower($path)));
+
+  return $path;
+}
+
+function process_release()
+{
+  global $FULL_RELEASE_PATH;
+
+  exec("rm -rf $FULL_RELEASE_PATH/build");
+  mkdir("$FULL_RELEASE_PATH/var");
+  exec("chmod 777 $FULL_RELEASE_PATH/var");
+  exec("chmod 777 $FULL_RELEASE_PATH/db");
+  exec("chmod 666 $FULL_RELEASE_PATH/db/sqlite.db");
+  exec("rm -f $FULL_RELEASE_PATH/settings/*.override.php");
+  exec("rm -f $FULL_RELEASE_PATH/*.override.php");
+}
+
+function make_archives()
+{
+  global $TAR;
+  global $RELEASE_NAME;
+  global $RELEASE_DIR;
+  global $FULL_RELEASE_PATH;
+
+  echo "Making release...\n";
+
+  $DIR = getcwd();
+
+  chdir($RELEASE_DIR);
+
+  echo "Tarring release...\n";
+
+  exec("tar -zcf $TAR $RELEASE_NAME");
+
+  chdir($DIR);
+}
+
+cleanup();
+
+export_project();
+
+process_release();
+
+make_archives();
+
+?>

Added: 3.x/examples/cms/cli/cron.php
===================================================================
--- 3.x/examples/cms/cli/cron.php	                        (rev 0)
+++ 3.x/examples/cms/cli/cron.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,30 @@
+<?php
+require_once(dirname(__FILE__) . '/../setup.php');
+set_time_limit(0);
+
+$dsn = lmbToolkit :: instance()->getDefaultDbDSN();
+
+$host = $dsn->getHost();
+$user = $dsn->getUser();
+$password = $dsn->getPassword();
+$database = $dsn->getDatabase();
+
+$sql = dirname(__FILE__) . '/../init/db.mysql';
+
+load($host, $user, $password, $database, $sql);
+
+function load($host, $user, $password, $database, $file)
+{
+  $cmd = "mysql -u$user -p$password -h$host --default-character-set=utf8 $database < $file";
+
+  echo "Starting loading '$file' file to '$database' DB...";
+
+  system($cmd, $ret);
+
+  if(!$ret)
+    echo "done! (" . filesize($file) . " bytes)\n";
+  else
+    echo "error!\n";
+}
+
+?>

Added: 3.x/examples/cms/cli/db_dump.php
===================================================================
--- 3.x/examples/cms/cli/db_dump.php	                        (rev 0)
+++ 3.x/examples/cms/cli/db_dump.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,33 @@
+<?php
+require_once(dirname(__FILE__) . '/../setup.php');
+set_time_limit(0);
+
+$dsn = lmbToolkit :: instance()->getDefaultDbDSN();
+
+$host = $dsn->getHost();
+$user = $dsn->getUser();
+$password = $dsn->getPassword();
+$database = $dsn->getDatabase();
+
+$production_sql = dirname(__FILE__) . '/../init/db.mysql';
+
+dump($host, $user, $password, $database, $production_sql);
+
+function dump($host, $user, $password, $database, $file)
+{
+  $cmd = "mysqldump -u$user -p$password -h$host $database " .
+         "--skip-opt --compact --add-drop-table --create-options --quick --set-charset " .
+         "--allow-keywords --max_allowed_packet=16M --quote-names " .
+         "--complete-insert --result-file=$file --default-character-set=utf8";
+
+  echo "Starting dumping to '$file' file...";
+
+  system($cmd, $ret);
+
+  if(!$ret)
+    echo "done! (" . filesize($file) . " bytes)\n";
+  else
+    echo "error!\n";
+}
+
+?>

Added: 3.x/examples/cms/cli/db_load.php
===================================================================
--- 3.x/examples/cms/cli/db_load.php	                        (rev 0)
+++ 3.x/examples/cms/cli/db_load.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,30 @@
+<?php
+require_once(dirname(__FILE__) . '/../setup.php');
+set_time_limit(0);
+
+$dsn = lmbToolkit :: instance()->getDefaultDbDSN();
+
+$host = $dsn->getHost();
+$user = $dsn->getUser();
+$password = $dsn->getPassword();
+$database = $dsn->getDatabase();
+
+$production_sql = dirname(__FILE__) . '/../init/db.mysql';
+
+load($host, $user, $password, $database, $production_sql);
+
+function load($host, $user, $password, $database, $file)
+{
+  $cmd = "mysql -u$user -p$password -h$host --default-character-set=utf8 $database < $file";
+
+  echo "Starting loading '$file' file to '$database' DB...";
+
+  system($cmd, $ret);
+
+  if(!$ret)
+    echo "done! (" . filesize($file) . " bytes)\n";
+  else
+    echo "error!\n";
+}
+
+?>

Added: 3.x/examples/cms/common.inc.php
===================================================================
--- 3.x/examples/cms/common.inc.php	                        (rev 0)
+++ 3.x/examples/cms/common.inc.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,11 @@
+<?php
+require_once('limb/core/common.inc.php');
+require_once('limb/i18n/common.inc.php');
+require_once('limb/i18n/utf8.inc.php');
+require_once('limb/web_app/common.inc.php');
+require_once('limb/cms/common.inc.php');
+require_once(dirname(__FILE__) . '/toolkit.inc.php');
+
+lmb_require(dirname(__FILE__) . '/src/model/*.class.php');
+
+?>
\ No newline at end of file


Property changes on: 3.x/examples/cms/settings
___________________________________________________________________
Name: svn:ignore
   + wact.conf.override.php


Added: 3.x/examples/cms/settings/db.conf.php
===================================================================
--- 3.x/examples/cms/settings/db.conf.php	                        (rev 0)
+++ 3.x/examples/cms/settings/db.conf.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,4 @@
+<?php
+
+$conf = array('dsn' => 'mysql://root:test@localhost/limb_cms?charset=utf8');
+?>
\ No newline at end of file

Added: 3.x/examples/cms/settings/navigation.conf.php
===================================================================
--- 3.x/examples/cms/settings/navigation.conf.php	                        (rev 0)
+++ 3.x/examples/cms/settings/navigation.conf.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,33 @@
+<?php
+lmb_require('limb/cms/src/model/lmbCmsUserRoles.class.php');
+
+$editor = array(array('title' => 'Content',
+                      'id' => 'content',
+                           'children' => array(
+                              array('title' => 'News', 'url' => '/admin_news'),
+                              array('title' => 'Text pages', 'url' => '/admin_documents'),
+                              )),
+                array('title' => 'Other',
+                      'id' => 'other',
+                           'children' => array(
+                              array('title' => 'Navigation', 'url' => '/admin_navigation'),
+                              )),
+                array('title' => 'Interactive',
+                      'id' => 'interactive',
+                           'children' => array(
+                              array('title' => 'Guestbook', 'url' => '/admin_guestbook'),
+                              ))
+  );
+
+$admin = array(array('title' => 'Administration',
+                     'id' => 'item1',
+                            'children' => array(
+                               array('title' => 'Users', 'url' => '/admin_user'),
+                               array('title' => 'Site structure', 'url' => '/admin_tree'),
+                               )));
+
+$conf = array(
+  lmbCmsUserRoles :: EDITOR  => $editor,
+  lmbCmsUserRoles :: ADMIN  => $admin,
+);
+?>

Added: 3.x/examples/cms/settings/wact.conf.php
===================================================================
--- 3.x/examples/cms/settings/wact.conf.php	                        (rev 0)
+++ 3.x/examples/cms/settings/wact.conf.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,8 @@
+<?php
+$conf = array(
+'forcescan' => false,  #Force to scan directories for tags, filters and properties (very slow)
+'forcecompile' => false #Force every template to be re-compiled on every request. Option is used
+                        #for debugging templates when developing template
+
+);
+?>

Added: 3.x/examples/cms/setup.override.php-example
===================================================================
--- 3.x/examples/cms/setup.override.php-example	                        (rev 0)
+++ 3.x/examples/cms/setup.override.php-example	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,10 @@
+<?php
+set_time_limit(0);
+restore_include_path();
+set_include_path(dirname(__FILE__) . '/' . PATH_SEPARATOR .
+                 'var/dev/limb/3.x/' . PATH_SEPARATOR .
+                 dirname(__FILE__) . '/lib/' . PATH_SEPARATOR);
+
+ at define('LIMB_CACHE_DB_META_IN_FILE', false);
+
+?>

Added: 3.x/examples/cms/setup.php
===================================================================
--- 3.x/examples/cms/setup.php	                        (rev 0)
+++ 3.x/examples/cms/setup.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,23 @@
+<?php
+set_include_path(dirname(__FILE__) . '/' . PATH_SEPARATOR .
+                 dirname(__FILE__) . '/lib/' . PATH_SEPARATOR);
+
+if(file_exists(dirname(__FILE__) . '/setup.override.php'))
+  require_once(dirname(__FILE__) . '/setup.override.php');
+
+ at define('LIMB_CACHE_DB_META_IN_FILE', true);
+ at define('LIMB_APP_MODE', 'production');
+ at define('LIMB_CMS_MEDIA_REPOSITORY_DIR', dirname(__FILE__) . '/www/media/');
+
+ at define('FEEDBACK_EMAIL', 'admin at example.com');
+
+ at define('LIMB_USE_PHPMAIL', false);
+ at define('LIMB_SMTP_PORT', '25');
+ at define('LIMB_SMTP_HOST', 'localhost');
+ at define('LIMB_SMTP_AUTH', false);
+ at define('LIMB_SMTP_USER', '');
+ at define('LIMB_SMTP_PASSWORD', '');
+
+require_once(dirname(__FILE__) . '/common.inc.php');
+
+?>

Added: 3.x/examples/cms/src/captcha/Captcha.class.php
===================================================================
--- 3.x/examples/cms/src/captcha/Captcha.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/captcha/Captcha.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,43 @@
+<?php
+ at define('CAPTCHA_SESSION_ID', 'limb_cms_secure_captcha');
+ at define('CAPTCHA_CHAR_SET', '0-9');
+ at define('CAPTCHA_NUM_CHARS', '2');
+require_once(dirname(__FILE__) . '/php-captcha.inc.php');
+
+class Captcha extends PhpCaptcha
+{
+  function GenerateCode()
+  {
+    // reset code
+    $item1 = $this->_generateItem();
+    $this->sCode = $item1;
+
+    $_SESSION[CAPTCHA_SESSION_ID] = (int)$item1;
+  }
+
+  function _generateItem()
+  {
+    $item = '';
+    // loop through and generate the code letter by letter
+    for ($i = 0; $i < $this->iNumChars; $i++)
+    {
+      if (count($this->aCharSet) > 0)
+      {
+         // select random character and add to code string
+         $item .= $this->aCharSet[array_rand($this->aCharSet)];
+      } else
+      {
+         // select random character and add to code string
+         $item .= chr(rand(65, 90));
+      }
+    }
+
+    return $item;
+  }
+
+  function CalculateSpacing() {
+     $this->iSpacing = (int)($this->iWidth / ($this->iNumChars * 2 + 2));
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/captcha/php-captcha.inc.php
===================================================================
--- 3.x/examples/cms/src/captcha/php-captcha.inc.php	                        (rev 0)
+++ 3.x/examples/cms/src/captcha/php-captcha.inc.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,486 @@
+<?php
+   /***************************************************************/
+   /* PhpCaptcha - A visual and audio CAPTCHA generation library
+
+      Software License Agreement (BSD License)
+
+      Copyright (C) 2005-2006, Edward Eliot.
+      All rights reserved.
+
+      Redistribution and use in source and binary forms, with or without
+      modification, are permitted provided that the following conditions are met:
+
+         * Redistributions of source code must retain the above copyright
+           notice, this list of conditions and the following disclaimer.
+         * Redistributions in binary form must reproduce the above copyright
+           notice, this list of conditions and the following disclaimer in the
+           documentation and/or other materials provided with the distribution.
+         * Neither the name of Edward Eliot nor the names of its contributors
+           may be used to endorse or promote products derived from this software
+           without specific prior written permission of Edward Eliot.
+
+      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND ANY
+      EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+      DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+      DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+      ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+      SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+      Last Updated:  18th April 2006                               */
+   /***************************************************************/
+
+   /************************ Documentation ************************/
+   /*
+
+   Documentation is available at http://www.ejeliot.com/pages/2
+
+   */
+   /************************ Default Options **********************/
+
+   // class defaults - change to effect globally
+
+   @define('CAPTCHA_SESSION_ID', 'php_captcha');
+   @define('CAPTCHA_WIDTH', 200); // max 500
+   @define('CAPTCHA_HEIGHT', 50); // max 200
+   @define('CAPTCHA_NUM_CHARS', 5);
+   @define('CAPTCHA_NUM_LINES', 70);
+   @define('CAPTCHA_CHAR_SHADOW', false);
+   @define('CAPTCHA_OWNER_TEXT', '');
+   @define('CAPTCHA_CHAR_SET', ''); // defaults to A-Z
+   @define('CAPTCHA_CASE_INSENSITIVE', true);
+   @define('CAPTCHA_BACKGROUND_IMAGES', '');
+   @define('CAPTCHA_MIN_FONT_SIZE', 16);
+   @define('CAPTCHA_MAX_FONT_SIZE', 25);
+   @define('CAPTCHA_USE_COLOUR', false);
+   @define('CAPTCHA_FILE_TYPE', 'jpeg');
+   @define('CAPTCHA_FLITE_PATH', '/usr/bin/flite');
+   @define('CAPTCHA_AUDIO_PATH', '/tmp/'); // must be writeable by PHP process
+
+   /************************ End Default Options **********************/
+
+   // don't edit below this line (unless you want to change the class!)
+
+   class PhpCaptcha {
+      var $oImage;
+      var $aFonts;
+      var $iWidth;
+      var $iHeight;
+      var $iNumChars;
+      var $iNumLines;
+      var $iSpacing;
+      var $bCharShadow;
+      var $sOwnerText;
+      var $aCharSet;
+      var $bCaseInsensitive;
+      var $vBackgroundImages;
+      var $iMinFontSize;
+      var $iMaxFontSize;
+      var $bUseColour;
+      var $sFileType;
+      var $sCode = '';
+
+      function PhpCaptcha(
+         $aFonts, // array of TrueType fonts to use - specify full path
+         $iWidth = CAPTCHA_WIDTH, // width of image
+         $iHeight = CAPTCHA_HEIGHT // height of image
+      ) {
+         // get parameters
+         $this->aFonts = $aFonts;
+         $this->SetNumChars(CAPTCHA_NUM_CHARS);
+         $this->SetNumLines(CAPTCHA_NUM_LINES);
+         $this->DisplayShadow(CAPTCHA_CHAR_SHADOW);
+         $this->SetOwnerText(CAPTCHA_OWNER_TEXT);
+         $this->SetCharSet(CAPTCHA_CHAR_SET);
+         $this->CaseInsensitive(CAPTCHA_CASE_INSENSITIVE);
+         $this->SetBackgroundImages(CAPTCHA_BACKGROUND_IMAGES);
+         $this->SetMinFontSize(CAPTCHA_MIN_FONT_SIZE);
+         $this->SetMaxFontSize(CAPTCHA_MAX_FONT_SIZE);
+         $this->UseColour(CAPTCHA_USE_COLOUR);
+         $this->SetFileType(CAPTCHA_FILE_TYPE);
+         $this->SetWidth($iWidth);
+         $this->SetHeight($iHeight);
+      }
+
+      function CalculateSpacing() {
+         $this->iSpacing = (int)($this->iWidth / $this->iNumChars);
+      }
+
+      function SetWidth($iWidth) {
+         $this->iWidth = $iWidth;
+         if ($this->iWidth > 500) $this->iWidth = 500; // to prevent perfomance impact
+         $this->CalculateSpacing();
+      }
+
+      function SetHeight($iHeight) {
+         $this->iHeight = $iHeight;
+         if ($this->iHeight > 200) $this->iHeight = 200; // to prevent performance impact
+      }
+
+      function SetNumChars($iNumChars) {
+         $this->iNumChars = $iNumChars;
+         $this->CalculateSpacing();
+      }
+
+      function SetNumLines($iNumLines) {
+         $this->iNumLines = $iNumLines;
+      }
+
+      function DisplayShadow($bCharShadow) {
+         $this->bCharShadow = $bCharShadow;
+      }
+
+      function SetOwnerText($sOwnerText) {
+         $this->sOwnerText = $sOwnerText;
+      }
+
+      function SetCharSet($vCharSet) {
+         // check for input type
+         if (is_array($vCharSet)) {
+            $this->aCharSet = $vCharSet;
+         } else {
+            if ($vCharSet != '') {
+               // split items on commas
+               $aCharSet = explode(',', $vCharSet);
+
+               // initialise array
+               $this->aCharSet = array();
+
+               // loop through items
+               foreach ($aCharSet as $sCurrentItem) {
+                  // a range should have 3 characters, otherwise is normal character
+                  if (strlen($sCurrentItem) == 3) {
+                     // split on range character
+                     $aRange = explode('-', $sCurrentItem);
+
+                     // check for valid range
+                     if (count($aRange) == 2 && $aRange[0] < $aRange[1]) {
+                        // create array of characters from range
+                        $aRange = range($aRange[0], $aRange[1]);
+
+                        // add to charset array
+                        $this->aCharSet = array_merge($this->aCharSet, $aRange);
+                     }
+                  } else {
+                     $this->aCharSet[] = $sCurrentItem;
+                  }
+               }
+            }
+         }
+      }
+
+      function CaseInsensitive($bCaseInsensitive) {
+         $this->bCaseInsensitive = $bCaseInsensitive;
+      }
+
+      function SetBackgroundImages($vBackgroundImages) {
+         $this->vBackgroundImages = $vBackgroundImages;
+      }
+
+      function SetMinFontSize($iMinFontSize) {
+         $this->iMinFontSize = $iMinFontSize;
+      }
+
+      function SetMaxFontSize($iMaxFontSize) {
+         $this->iMaxFontSize = $iMaxFontSize;
+      }
+
+      function UseColour($bUseColour) {
+         $this->bUseColour = $bUseColour;
+      }
+
+      function SetFileType($sFileType) {
+         // check for valid file type
+         if (in_array($sFileType, array('gif', 'png', 'jpeg'))) {
+            $this->sFileType = $sFileType;
+         } else {
+            $this->sFileType = 'jpeg';
+         }
+      }
+
+      function DrawLines() {
+         for ($i = 0; $i < $this->iNumLines; $i++) {
+            // allocate colour
+            if ($this->bUseColour) {
+               $iLineColour = imagecolorallocate($this->oImage, rand(100, 250), rand(100, 250), rand(100, 250));
+            } else {
+               $iRandColour = rand(100, 250);
+               $iLineColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
+            }
+
+            // draw line
+            imageline($this->oImage, rand(0, $this->iWidth), rand(0, $this->iHeight), rand(0, $this->iWidth), rand(0, $this->iHeight), $iLineColour);
+         }
+      }
+
+      function DrawOwnerText() {
+         // allocate owner text colour
+         $iBlack = imagecolorallocate($this->oImage, 0, 0, 0);
+         // get height of selected font
+         $iOwnerTextHeight = imagefontheight(2);
+         // calculate overall height
+         $iLineHeight = $this->iHeight - $iOwnerTextHeight - 4;
+
+         // draw line above text to separate from CAPTCHA
+         imageline($this->oImage, 0, $iLineHeight, $this->iWidth, $iLineHeight, $iBlack);
+
+         // write owner text
+         imagestring($this->oImage, 2, 3, $this->iHeight - $iOwnerTextHeight - 3, $this->sOwnerText, $iBlack);
+
+         // reduce available height for drawing CAPTCHA
+         $this->iHeight = $this->iHeight - $iOwnerTextHeight - 5;
+      }
+
+      function GenerateCode() {
+         // reset code
+         $this->sCode = '';
+
+         // loop through and generate the code letter by letter
+         for ($i = 0; $i < $this->iNumChars; $i++) {
+            if (count($this->aCharSet) > 0) {
+               // select random character and add to code string
+               $this->sCode .= $this->aCharSet[array_rand($this->aCharSet)];
+            } else {
+               // select random character and add to code string
+               $this->sCode .= chr(rand(65, 90));
+            }
+         }
+
+         // save code in session variable
+         if ($this->bCaseInsensitive) {
+            $_SESSION[CAPTCHA_SESSION_ID] = strtoupper($this->sCode);
+         } else {
+            $_SESSION[CAPTCHA_SESSION_ID] = $this->sCode;
+         }
+      }
+
+      function DrawCharacters() {
+         // loop through and write out selected number of characters
+         for ($i = 0; $i < strlen($this->sCode); $i++) {
+            // select random font
+            $sCurrentFont = $this->aFonts[array_rand($this->aFonts)];
+
+            // select random colour
+            if ($this->bUseColour) {
+               $iTextColour = imagecolorallocate($this->oImage, rand(0, 100), rand(0, 100), rand(0, 100));
+
+               if ($this->bCharShadow) {
+                  // shadow colour
+                  $iShadowColour = imagecolorallocate($this->oImage, rand(0, 100), rand(0, 100), rand(0, 100));
+               }
+            } else {
+               $iRandColour = rand(0, 100);
+               $iTextColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
+
+               if ($this->bCharShadow) {
+                  // shadow colour
+                  $iRandColour = rand(0, 100);
+                  $iShadowColour = imagecolorallocate($this->oImage, $iRandColour, $iRandColour, $iRandColour);
+               }
+            }
+
+            // select random font size
+            $iFontSize = rand($this->iMinFontSize, $this->iMaxFontSize);
+
+            // select random angle
+            $iAngle = rand(-30, 30);
+
+            // get dimensions of character in selected font and text size
+            $aCharDetails = imageftbbox($iFontSize, $iAngle, $sCurrentFont, $this->sCode[$i], array());
+
+            // calculate character starting coordinates
+            $iX = $this->iSpacing / 4 + $i * $this->iSpacing;
+            $iCharHeight = $aCharDetails[2] - $aCharDetails[5];
+            $iY = $this->iHeight / 2 + $iCharHeight / 4;
+
+            // write text to image
+            imagefttext($this->oImage, $iFontSize, $iAngle, $iX, $iY, $iTextColour, $sCurrentFont, $this->sCode[$i], array());
+
+            if ($this->bCharShadow) {
+               $iOffsetAngle = rand(-30, 30);
+
+               $iRandOffsetX = rand(-5, 5);
+               $iRandOffsetY = rand(-5, 5);
+
+               imagefttext($this->oImage, $iFontSize, $iOffsetAngle, $iX + $iRandOffsetX, $iY + $iRandOffsetY, $iShadowColour, $sCurrentFont, $this->sCode[$i], array());
+            }
+         }
+      }
+
+      function WriteFile($sFilename) {
+         if ($sFilename == '') {
+            // tell browser that data is jpeg
+            header("Content-type: image/$this->sFileType");
+         }
+
+         switch ($this->sFileType) {
+            case 'gif':
+               $sFilename != '' ? imagegif($this->oImage, $sFilename) : imagegif($this->oImage);
+               break;
+            case 'png':
+               $sFilename != '' ? imagepng($this->oImage, $sFilename) : imagepng($this->oImage);
+               break;
+            default:
+               $sFilename != '' ? imagejpeg($this->oImage, $sFilename) : imagejpeg($this->oImage);
+         }
+      }
+
+      function Create($sFilename = '') {
+         // check for required gd functions
+         if (!function_exists('imagecreate') || !function_exists("image$this->sFileType") || ($this->vBackgroundImages != '' && !function_exists('imagecreatetruecolor'))) {
+            return false;
+         }
+
+         // get background image if specified and copy to CAPTCHA
+         if (is_array($this->vBackgroundImages) || $this->vBackgroundImages != '') {
+            // create new image
+            $this->oImage = imagecreatetruecolor($this->iWidth, $this->iHeight);
+
+            // create background image
+            if (is_array($this->vBackgroundImages)) {
+               $iRandImage = array_rand($this->vBackgroundImages);
+               $oBackgroundImage = imagecreatefromjpeg($this->vBackgroundImages[$iRandImage]);
+            } else {
+               $oBackgroundImage = imagecreatefromjpeg($this->vBackgroundImages);
+            }
+
+            // copy background image
+            imagecopy($this->oImage, $oBackgroundImage, 0, 0, 0, 0, $this->iWidth, $this->iHeight);
+
+            // free memory used to create background image
+            imagedestroy($oBackgroundImage);
+         } else {
+            // create new image
+            $this->oImage = imagecreate($this->iWidth, $this->iHeight);
+         }
+
+         // allocate white background colour
+         imagecolorallocate($this->oImage, 255, 255, 255);
+
+         // check for owner text
+         if ($this->sOwnerText != '') {
+            $this->DrawOwnerText();
+         }
+
+         // check for background image before drawing lines
+         if (!is_array($this->vBackgroundImages) && $this->vBackgroundImages == '') {
+            $this->DrawLines();
+         }
+
+         $this->GenerateCode();
+         $this->DrawCharacters();
+
+         // write out image to file or browser
+         $this->WriteFile($sFilename);
+
+         // free memory used in creating image
+         imagedestroy($this->oImage);
+
+         return true;
+      }
+
+      // call this method statically
+      function Validate($sUserCode, $bCaseInsensitive = true) {
+         if ($bCaseInsensitive) {
+            $sUserCode = strtoupper($sUserCode);
+         }
+
+         if (!empty($_SESSION[CAPTCHA_SESSION_ID]) && $sUserCode == $_SESSION[CAPTCHA_SESSION_ID]) {
+            // clear to prevent re-use
+            unset($_SESSION[CAPTCHA_SESSION_ID]);
+
+            return true;
+         }
+
+         return false;
+      }
+   }
+
+   // this class will only work correctly if a visual CAPTCHA has been created first using PhpCaptcha
+   class AudioPhpCaptcha {
+      var $sFlitePath;
+      var $sAudioPath;
+      var $sCode;
+
+      function AudioPhpCaptcha(
+         $sFlitePath = CAPTCHA_FLITE_PATH, // path to flite binary
+         $sAudioPath = CAPTCHA_AUDIO_PATH // the location to temporarily store the generated audio CAPTCHA
+      ) {
+         $this->SetFlitePath($sFlitePath);
+         $this->SetAudioPath($sAudioPath);
+
+         // retrieve code if already set by previous instance of visual PhpCaptcha
+         if (isset($_SESSION[CAPTCHA_SESSION_ID])) {
+            $this->sCode = $_SESSION[CAPTCHA_SESSION_ID];
+         }
+      }
+
+      function SetFlitePath($sFlitePath) {
+         $this->sFlitePath = $sFlitePath;
+      }
+
+      function SetAudioPath($sAudioPath) {
+         $this->sAudioPath = $sAudioPath;
+      }
+
+      function Mask($sText) {
+         $iLength = strlen($sText);
+
+         // loop through characters in code and format
+         $sFormattedText = '';
+         for ($i = 0; $i < $iLength; $i++) {
+            // comma separate all but first and last characters
+            if ($i > 0 && $i < $iLength - 1) {
+               $sFormattedText .= ', ';
+            } elseif ($i == $iLength - 1) { // precede last character with "and"
+               $sFormattedText .= ' and ';
+            }
+            $sFormattedText .= $sText[$i];
+         }
+
+         $aPhrases = array(
+            "The %1\$s characters are as follows: %2\$s",
+            "%2\$s, are the %1\$s letters",
+            "Here are the %1\$s characters: %2\$s",
+            "%1\$s characters are: %2\$s",
+            "%1\$s letters: %2\$s"
+         );
+
+         $iPhrase = array_rand($aPhrases);
+
+         return sprintf($aPhrases[$iPhrase], $iLength, $sFormattedText);
+      }
+
+      function Create() {
+         $sText = $this->Mask($this->sCode);
+         $sFile = md5($this->sCode.time());
+
+         // create file with flite
+         shell_exec("$this->sFlitePath -t \"$sText\" -o $this->sAudioPath$sFile.wav");
+
+         // set headers
+         header('Content-type: audio/x-wav');
+         header("Content-Disposition: attachment;filename=$sFile.wav");
+
+         // output to browser
+         echo file_get_contents("$this->sAudioPath$sFile.wav");
+
+         // delete temporary file
+         @unlink("$this->sAudioPath$sFile.wav");
+      }
+   }
+
+   // example sub class
+   class PhpCaptchaColour extends PhpCaptcha {
+      function PhpCaptchaColour($aFonts, $iWidth = CAPTCHA_WIDTH, $iHeight = CAPTCHA_HEIGHT) {
+         // call parent constructor
+         parent::PhpCaptcha($aFonts, $iWidth, $iHeight);
+
+         // set options
+         $this->UseColour(true);
+      }
+   }
+?>

Added: 3.x/examples/cms/src/controller/AdminCatalogCategoryController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/AdminCatalogCategoryController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/AdminCatalogCategoryController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,11 @@
+<?php
+lmb_require('limb/cms/src/controller/AdminNodeWithObjectController.class.php');
+
+class AdminCatalogCategoryController extends AdminNodeWithObjectController
+{
+  protected $_object_class_name = 'CatalogCategory';
+  protected $_controller_name = 'catalog_category';
+  protected $_form_name = 'catalog_category_form';
+}
+
+?>

Added: 3.x/examples/cms/src/controller/AdminCatalogItemController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/AdminCatalogItemController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/AdminCatalogItemController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,20 @@
+<?php
+lmb_require('limb/cms/src/controller/AdminNodeWithObjectController.class.php');
+
+class AdminCatalogItemController extends AdminNodeWithObjectController
+{
+  protected $_object_class_name = 'CatalogItem';
+  protected $_controller_name = 'catalog_item';
+  protected $_form_name = 'catalog_item_form';
+
+  protected function _onBeforeCreate()
+  {
+    if($parent = $this->node->getParent())
+    {
+      $this->item->setCategory($parent->getObject());
+      $this->node->setIdentifier(CatalogItem :: generateIdentifier($parent));
+    }
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/controller/AdminFeedbackMessageController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/AdminFeedbackMessageController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/AdminFeedbackMessageController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,44 @@
+<?php
+lmb_require('limb/cms/src/controller/AdminObjectController.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/cms/src/controller/lmbCmsAdminFilterHelper.class.php');
+
+class AdminFeedbackMessageController extends AdminObjectController
+{
+  protected $_object_class_name = 'FeedbackMessage';
+  protected $_form_name = 'feedback_form';
+
+  function doDisplay()
+  {
+    $this->useForm('filter_form');
+    $day = 24*60*60;
+
+    $filter_helper = new lmbCmsAdminFilterHelper('ADMIN_FEEDBACK_FILTER');
+
+    $this->setFormDatasource($this->request);
+
+    if(!$this->request->hasPost())
+    {
+      $locale = $this->toolkit->getLocaleObject();
+
+      $filter_helper->setFilter('start_date', lmbDate :: stampToISO(time() - 7 * $day));
+      $filter_helper->setFilter('finish_date', lmbDate :: stampToISO(time()));
+      $filter_helper->setFilter('status', '');
+    }
+    else
+    {
+      $filter_helper->setFilter('start_date');
+      $filter_helper->setFilter('finish_date');
+      $filter_helper->setFilter('status');
+      $this->toolkit->redirect();
+    }
+  }
+
+  function _onBeforeSave()
+  {
+    if(!$this->item->getDateCommented())
+      $this->item->setDateCommented(time());
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/controller/AdminNewsController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/AdminNewsController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/AdminNewsController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,55 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/cms/src/controller/lmbCmsAdminFilterHelper.class.php');
+
+class AdminNewsController extends lmbController
+{
+  function doDisplay()
+  {
+    $this->useForm('filter_form');
+    $day = 24*60*60;
+
+    $filter_helper = new rtAdminFilterHelper('ADMIN_NEWS_FILTER');
+
+    $this->setFormDatasource($this->request);
+
+    if(!$this->request->hasPost())
+    {
+      $filter_helper->setFilter('start_date', lmbDate :: stampToISO(time() - 14 * $day));
+      $filter_helper->setFilter('finish_date', lmbDate :: stampToISO(time()));
+      $filter_helper->setFilter('status', '');
+    }
+    else
+    {
+      $filter_helper->setFilter('start_date');
+      $filter_helper->setFilter('finish_date');
+      $filter_helper->setFilter('status');
+      $this->toolkit->redirect();
+    }
+  }
+
+  protected function _import($item)
+  {
+    $item->import($this->request);
+
+    $uploaded = $this->request->getFile('large_image');
+
+    if(!$uploaded || !$uploaded->isValid())
+      return;
+
+    $storage = new rtFileStorage(LIMB_CMS_MEDIA_REPOSITORY_DIR . '/news');
+    $large_image_id = $storage->storeFile($uploaded->getTmpName(), $uploaded->getMimeType());
+    $item->setLargeImageId($large_image_id);
+
+    $image_object = new rtImage($uploaded->getTmpName(), $uploaded->getMimeType());
+    $image_object->resize(100);
+
+    $small_image_id = $storage->storeFile($image_object->getFilePath(), $uploaded->getMimeType());
+    $item->setSmallImageId($small_image_id);
+
+    $image_object->cleanup();
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/controller/AdminPollController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/AdminPollController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/AdminPollController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,119 @@
+<?php
+lmb_require('limb/cms/src/controller/AdminObjectController.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/cms/src/controller/lmbCmsAdminFilterHelper.class.php');
+
+class AdminPollController extends AdminObjectController
+{
+  protected $form_name = 'poll_form';
+  protected $_object_class_name = 'Poll';
+
+  function doDisplay()
+  {
+    $this->useForm('filter_form');
+    $day = 24*60*60;
+
+    $this->setFormDatasource($this->request);
+
+    $filter_helper = new rtAdminFilterHelper('ADMIN_POLL_FILTER');
+
+    if(!$this->request->hasPost())
+    {
+      $locale = $this->toolkit->getLocaleObject();
+
+      $filter_helper->setFilter('start_date', lmbDate :: stampToISO(time() - 30 * $day));
+      $filter_helper->setFilter('finish_date', lmbDate :: stampToISO(time()));
+      $filter_helper->setFilter('status', 0);
+    }
+    else
+    {
+      $filter_helper->setFilter('start_date');
+      $filter_helper->setFilter('finish_date');
+      $filter_helper->setFilter('status');
+      $this->toolkit->redirect();
+    }
+  }
+
+  protected function _import()
+  {
+    parent :: _import();
+
+    $this->_saveAnswers();
+  }
+
+  protected function _saveAnswers()
+  {
+    $answers = array();
+
+    $answer_ids = $this->request->getArray('answers_ids');
+    $old_answers_ids = $item->getAnswers()->getIds();
+
+    foreach($this->request->getArray('answers_titles') as $id => $title)
+    {
+      if(!$title)
+        continue;
+
+      $key = array_search($answer_ids[$id], $old_answers_ids);
+      if($key !== false)
+      {
+        $answer = new PollAnswer((int)$old_answers_ids[$key]);
+        unset($old_answers_ids[$key]);
+      }
+      else
+      {
+        $answer = new PollAnswer();
+        $answer->setPoll($item);
+      }
+
+      $answer->setTitle($title);
+      $answers[] = $answer;
+    }
+
+    $this->item->setAnswers($answers);
+  }
+
+  function doActivate()
+  {
+    $this->_doChangeStatus('activate');
+  }
+
+  function doDeactivate()
+  {
+    $this->_doChangeStatus('deactivate');
+  }
+
+  function doArchive()
+  {
+    $this->_doChangeStatus('archive');
+  }
+
+  protected function _doChangeStatus($status)
+  {
+    $ids = $this->request->get('ids');
+
+    if(!is_array($ids) || !count($ids))
+      return;
+
+    foreach($ids as $id)
+    {
+      $poll = new Poll((int)$id);
+      switch($status)
+      {
+        case "activate":
+          $poll->deactivate();
+        break;
+        case "deactivate":
+          $poll->deactivate();
+        break;
+        case "archive":
+          $poll->deactivate();
+        break;
+        default:
+         throw new lmbException('Wrong status');
+        break;
+      }
+    }
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/controller/CatalogController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/CatalogController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/CatalogController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,8 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+
+class CatalogController extends lmbController
+{
+}
+
+?>

Added: 3.x/examples/cms/src/controller/CatalogItemController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/CatalogItemController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/CatalogItemController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,8 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+
+class CatalogItemController extends lmbController
+{
+}
+
+?>

Added: 3.x/examples/cms/src/controller/FeedbackController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/FeedbackController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/FeedbackController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,73 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+lmb_require('limb/mail/src/lmbMailer.class.php');
+
+class FeedbackController extends lmbController
+{
+  function doDisplay()
+  {
+    $item = new FeedbackMessage();
+    $this->useForm('feedback_form');
+    $this->setFormDatasource($item);
+
+    if(!$this->request->hasPost())
+    {
+      $item->setConfirmCode('');
+      return;
+    }
+
+    $item->setFirstName($this->request->get('first_name'));
+    $item->setLastName($this->request->get('last_name'));
+    $item->setEmail($this->request->get('email'));
+    $item->setMessage($this->request->get('message'));
+    $item->setIpAddress($_SERVER['REMOTE_ADDR']);
+
+    $item->validate($this->error_list);
+    $this->_validate();
+
+    if(!$this->error_list->isValid())
+    {
+      $item->setConfirmCode('');
+      return;
+    }
+
+    if(!$item->trySave($this->error_list))
+    {
+      $item->setConfirmCode('');
+      return;
+    }
+
+    $this->_notifyAdministratorByEmail($item);
+    $this->redirect($this->request->getUriPath() . '?action=message_accepted');
+  }
+
+  protected function _notifyAdministratorByEmail($message)
+  {
+    $template = new lmbWactView('feedback/message_mail.html');
+    $template->setCacheDir(LIMB_VAR_DIR . '/compiled/');
+    $template->set('message', $message);
+
+    $email_body = $template->render();
+
+    $mailer = new lmbMailer();
+    $mailer->sendPlainMail(FEEDBACK_EMAIL,
+                           FEEDBACK_EMAIL,
+                           "Новое сообщение на сайте " . $_SERVER['SERVER_NAME'],
+                           $email_body);
+  }
+
+
+  protected function _validate()
+  {
+    $validator = new lmbValidator();
+    $validator->addRequiredRule('confirm_code');
+    lmb_require('src/validation/CaptchaRule.class.php');
+    $validator->addRule(new CaptchaRule('confirm_code'));
+
+    $validator->setErrorList($this->error_list);
+    $validator->validate($this->request);
+
+    return $validator->isValid();
+  }
+}
+?>
\ No newline at end of file

Added: 3.x/examples/cms/src/controller/NewsController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/NewsController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/NewsController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,8 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+
+class NewsController extends lmbController
+{
+}
+
+?>

Added: 3.x/examples/cms/src/controller/PollController.class.php
===================================================================
--- 3.x/examples/cms/src/controller/PollController.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/controller/PollController.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,20 @@
+<?php
+lmb_require('limb/web_app/src/controller/lmbController.class.php');
+
+class PollController extends lmbController
+{
+  function doVote()
+  {
+    $this->setTemplate('poll/results.html');
+
+    if(!$poll = lmbActiveRecord :: find('rtPoll', (int)$this->request->get('poll_id')))
+      return $this->forwardTo404();
+
+    if($poll->canVote())
+      $poll->vote($this->request->get('answer'));
+    else
+      $this->passToView('vote_restrict', true);
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/model/CatalogCategory.class.php
===================================================================
--- 3.x/examples/cms/src/model/CatalogCategory.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/CatalogCategory.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,12 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+lmb_require('src/model/CatalogItem.class.php');
+
+class CatalogCategory extends lmbActiveRecord
+{
+  protected $_has_one = array('node' => array('field' => 'node_id',
+                                              'class' => 'lmbCmsNode'));
+
+  protected $_has_many = array('items' => array('class' => 'CatalogItem', 'field' => 'category_id'));
+}
+?>

Added: 3.x/examples/cms/src/model/CatalogItem.class.php
===================================================================
--- 3.x/examples/cms/src/model/CatalogItem.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/CatalogItem.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,46 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+lmb_require('src/model/CatalogCats.class.php');
+
+class CatalogItem extends lmbActiveRecord
+{
+  protected $_many_belongs_to = array('node' => array('field' => 'node_id',
+                                                      'class' => 'lmbCmsNode'),
+                                      'category' => array('field' => 'category_id',
+                                                          'class' => 'CatalogCategory'));
+
+  static function generateIdentifier($parent_id)
+  {
+    $identifier = self :: getMaxChildIdentifier($parent_id);
+
+    if($identifier === false)
+      return 1;
+
+    if(preg_match('/(.*?)(\d+)$/', $identifier, $matches))
+      $new_identifier = $matches[1] . ($matches[2] + 1);
+    else
+      $new_identifier = '1';
+
+    return $new_identifier;
+  }
+
+  static function getMaxChildIdentifier($node)
+  {
+    if(!$parent = lmbCmsNode :: findById($node))
+      return false;
+
+    $children = lmbCmsNode :: findChildren($parent['id']);
+    $identifiers = array();
+    foreach($children as $child)
+      $identifiers[] = $child['identifier'];
+
+    if(count($identifiers))
+    {
+      uasort($identifiers, 'strnatcmp');
+      return end($identifiers);
+    }
+    else
+      return 0;
+  }
+}
+?>

Added: 3.x/examples/cms/src/model/FeedbackMessage.class.php
===================================================================
--- 3.x/examples/cms/src/model/FeedbackMessage.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/FeedbackMessage.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,55 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/dbal/src/criteria/lmbSQLCriteria.class.php');
+lmb_require('limb/dbal/src/criteria/lmbSQLFieldBetweenCriteria.class.php');
+
+class FeedbackMessage extends lmbActiveRecord
+{
+  protected function _createValidator()
+  {
+    $validator = new lmbValidator();
+    $validator->addRequiredRule('first_name');
+    $validator->addRequiredRule('last_name');
+    if($this->isNew())
+      $validator->addRequiredRule('email');
+    lmb_require('limb/validation/src/rule/lmbEmailRule.class.php');
+    $validator->addRule(new lmbEmailRule('email'));
+    $validator->addRequiredRule('message');
+    return $validator;
+  }
+
+  function getFullName()
+  {
+    return $this->getFirstName() . ' ' . $this->getLastName();
+  }
+
+  static function findForAdmin()
+  {
+    $toolkit = lmbToolkit :: instance();
+    $params = $toolkit->getSession()->get('ADMIN_FEEDBACK_FILTER', array());
+
+    $criteria = new lmbSQLCriteria();
+
+    if(isset($params['status']) && ($params['status'] !== ''))
+      $criteria->addAnd(array('is_published=?', $params['status']));
+
+    if($toolkit->getRequest()->get('uncommented'))
+      $criteria->addAnd('comment = ""');
+
+    if(isset($params['start_date']) && isset($params['finish_date']))
+    {
+      $locale = $toolkit->getLocaleObject();
+
+      $start_date = new lmbDate($params['start_date']);
+      $finish_date = new lmbDate($params['finish_date']);
+      $criteria->addAnd(lmbSQLCriteria :: between('date_created',
+                                                  $start_date->getStamp(),
+                                                  $finish_date->getEndOfDay()->getStamp()));
+    }
+
+    return lmbActiveRecord :: find('FeedbackMessage', $criteria);
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/model/News.class.php
===================================================================
--- 3.x/examples/cms/src/model/News.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/News.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,59 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/validation/src/rule/lmbDateRule.class.php');
+
+class News extends lmbActiveRecord
+{
+  protected $_lazy_attributes = array('content');
+
+  protected $_composed_of = array('date' => array('field' => 'date',
+                                                  'class' => 'lmbDate',
+                                                  'getter' => 'getStamp'));
+
+  protected function _createValidator()
+  {
+    $validator = new lmbValidator();
+    $validator->addRequiredRule('title');
+    $validator->addRequiredRule('annotation');
+    $validator->addRequiredRule('content');
+    $validator->addRequiredRule('iso_date');
+    $validator->addRule(new lmbDateRule('iso_date'));
+    return $validator;
+  }
+
+  protected function _onBeforeSave()
+  {
+    if($this->iso_date)
+      $this->setDate(new lmbDate($this->iso_date));
+  }
+
+  function getIsoDate()
+  {
+    if($this->iso_date === null)
+    {
+      if($date = $this->getDate())
+        $this->iso_date = $date->getIsoDate(false);
+      else
+        $this->iso_date = lmbDate :: create()->getIsoDate(false);
+    }
+    return $this->iso_date;
+  }
+
+  function setIsoDate($date)
+  {
+    $this->iso_date = $date;
+  }
+
+  function getPrevNews()
+  {
+    return lmbActiveRecord :: findFirst('News', array('criteria' => 'date < "'.$this->getDate()->getStamp().'"', 'sort' => array('date' => 'DESC')));
+  }
+
+  function getNextNews()
+  {
+    return lmbActiveRecord :: findFirst('News', array('criteria' => 'date > "'.$this->getDate()->getStamp().'"', 'sort' => array('date' => 'ASC')));
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/model/Poll.class.php
===================================================================
--- 3.x/examples/cms/src/model/Poll.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/Poll.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,183 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+lmb_require('limb/datetime/src/lmbDate.class.php');
+lmb_require('limb/dbal/src/criteria/lmbSQLCriteria.class.php');
+
+class Poll extends lmbActiveRecord
+{
+  protected $_has_many = array('answers' => array('field' => 'poll_id',
+                                                  'class' => 'PollAnswer'));
+
+  const STATUS_NOT_ACTIVE = 1;
+  const STATUS_ACTIVE = 2;
+  const STATUS_ARCHIVED = 3;
+
+  static protected $_statuses = array(1 => 'Не активный',
+                                      2 => 'Активный',
+                                      3 => 'В архиве');
+
+
+  protected function _createValidator()
+  {
+    $validator = new lmbValidator();
+    $validator->addRequiredRule('question');
+    return $validator;
+  }
+
+  static function translateStatus($status)
+  {
+    if(isset(self :: $_statuses[$status]))
+      return self :: $_statuses[$status];
+  }
+
+  function getStatusTitle()
+  {
+    return self :: translateStatus($this->getStatus());
+  }
+
+  static function getStatuses()
+  {
+    return self :: $_statuses;
+  }
+
+  function activate()
+  {
+    $this->setStatus(self :: STATUS_ACTIVE);
+    $this->save();
+  }
+
+  function isActive()
+  {
+    return $this->getStatus() == self :: STATUS_ACTIVE;
+  }
+
+  function getIsActive()
+  {
+    return $this->isActive();
+  }
+
+  function deactivate()
+  {
+    $this->setStatus(self :: STATUS_NOT_ACTIVE);
+    $this->save();
+  }
+
+  function archive()
+  {
+    $this->setStatus(self :: STATUS_ARCHIVED);
+    $this->save();
+  }
+
+  function vote($answer)
+  {
+    if(!$this->canVote())
+      return;
+
+    if(!is_object($answer))
+    {
+      $answer = new PollAnswer((int)$answer);
+
+      if($answer->getPoll()->getId() != $this->getId())
+        throw new lmbException('Wrong poll!');
+    }
+
+    $answer->setCount($answer->getCount() + 1);
+    $answer->save();
+
+    $response = lmbToolkit :: instance()->getResponse();
+    $week = time() + 60 * 60 * 24 * 7;
+    $response->setCookie('poll_' . $this->getId() . '_voted', true, $week);
+  }
+
+  function canVote()
+  {
+    $status = $this->getStatus();
+    if(($status == self :: STATUS_NOT_ACTIVE) || ($status == self :: STATUS_ARCHIVED))
+      return false;
+
+    $reuqest = lmbToolkit :: instance()->getRequest();
+    if($reuqest->getCookie('poll_' . $this->getId() . '_voted'))
+      return false;
+    else
+      return true;
+  }
+
+  function getCanVote()
+  {
+    return $this->canVote();
+  }
+
+  function getTotalCount()
+  {
+    $total = 0;
+    foreach($this->getAnswers() as $answer)
+      $total += $answer->getCount();
+
+    return $total;
+  }
+
+  function getRoundedAnswers()
+  {
+    $total_count = $this->getTotalCount();
+    $answers = $this->getAnswers();
+
+    $total = 0;
+    $result = array();
+
+    foreach($answers as $answer)
+    {
+      $answer_result = round($answer->getCount() / $total_count * 100);
+      if($total + $answer_result > 100)
+        $answer_result = 100 - $total;
+
+      $answer->set('percentage', $answer_result);
+      $total += $answer_result;
+      $result[] = $answer;
+    }
+
+    if($total < 100)
+    {
+      $last_answer = array_pop($result);
+      $last_answer->set('percentage', $last_answer->get('percentage') + (100 - $total));
+      $result[] = $last_answer;
+    }
+
+    return $result;
+  }
+
+  static function findActive()
+  {
+    return lmbActiveRecord :: find('Poll', "status = " . self :: STATUS_ACTIVE);
+  }
+
+  static function findArchived()
+  {
+    return lmbActiveRecord :: find('Poll', "status = " . self :: STATUS_ARCHIVED);
+  }
+
+  static function findForAdmin()
+  {
+    $toolkit = lmbToolkit :: instance();
+    $params = $toolkit->getSession()->get('ADMIN_POLL_FILTER', array());
+
+    $criteria = new lmbSQLCriteria();
+
+    if(isset($params['status']) && ($status = $params['status']))
+      $criteria->addAnd(array('status=?', $status));
+
+    if(isset($params['start_date']) && isset($params['finish_date']))
+    {
+      $locale = $toolkit->getLocaleObject();
+
+      $start_date = new lmbDate($params['start_date']);
+      $finish_date = new lmbDate($params['finish_date']);
+      $criteria->addAnd(new lmbSQLCriteria :: between('date_created',
+                                                      $start_date->getStamp(),
+                                                      $finish_date->getEndOfDay()->getStamp()));
+    }
+
+    return lmbActiveRecord :: find('Poll', $criteria);
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/model/PollAnswer.class.php
===================================================================
--- 3.x/examples/cms/src/model/PollAnswer.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/model/PollAnswer.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,17 @@
+<?php
+lmb_require('limb/active_record/src/lmbActiveRecord.class.php');
+
+class PollAnswer extends lmbActiveRecord
+{
+  protected $_many_belongs_to = array('poll' => array('field' => 'poll_id',
+                                                      'class' => 'Poll'));
+
+  protected function _createValidator()
+  {
+    $validator = new lmbValidator();
+    $validator->addRequiredRule('title');
+    return $validator;
+  }
+}
+
+?>

Added: 3.x/examples/cms/src/validation/CaptchaRule.class.php
===================================================================
--- 3.x/examples/cms/src/validation/CaptchaRule.class.php	                        (rev 0)
+++ 3.x/examples/cms/src/validation/CaptchaRule.class.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,23 @@
+<?php
+lmb_require('limb/validation/src/rule/lmbSingleFieldRule.class.php');
+require_once('src/captcha/Captcha.class.php');
+
+class CaptchaRule extends lmbSingleFieldRule
+{
+  function check($value)
+  {
+    if(!isset($_SESSION[CAPTCHA_SESSION_ID]))
+    {
+      $this->error('Entered code does not match result of operation which displayed on image');
+      return;
+    }
+
+    if(isset($value) && !empty($value))
+    {
+      if($value != $_SESSION[CAPTCHA_SESSION_ID])
+        $this->error('Entered code does not match result of operation which displayed on image');
+    }
+  }
+}
+
+?>
\ No newline at end of file

Added: 3.x/examples/cms/toolkit.inc.php
===================================================================
--- 3.x/examples/cms/toolkit.inc.php	                        (rev 0)
+++ 3.x/examples/cms/toolkit.inc.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,25 @@
+<?php
+/*
+ * Limb PHP Framework
+ *
+ * @link http://limb-project.com
+ * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
+ * @license    LGPL http://www.gnu.org/copyleft/lesser.html
+ */
+
+/**
+ * @package web_app
+ * @version $Id: toolkit.inc.php 5969 2007-06-08 10:51:09Z pachanga $
+ */
+lmb_require('limb/net/toolkit.inc.php');
+lmb_require('limb/i18n/toolkit.inc.php');
+lmb_require('limb/config/toolkit.inc.php');
+lmb_require('limb/fs/toolkit.inc.php');
+lmb_require('limb/view/toolkit.inc.php');
+lmb_require('limb/log/toolkit.inc.php');
+
+lmb_require('limb/toolkit/src/lmbToolkit.class.php');
+lmb_require('limb/web_app/src/toolkit/lmbWebAppTools.class.php');
+lmbToolkit :: merge(new lmbWebAppTools());
+
+?>
\ No newline at end of file

Added: 3.x/examples/cms/www/.htaccess
===================================================================
--- 3.x/examples/cms/www/.htaccess	                        (rev 0)
+++ 3.x/examples/cms/www/.htaccess	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,9 @@
+Allow from all
+
+RewriteEngine On
+
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteCond %{REQUEST_FILENAME} !-s
+RewriteCond %{REQUEST_FILENAME} !-l
+RewriteRule ^(.+)$ index.php?%{QUERY_STRING} [L]

Added: 3.x/examples/cms/www/favicon.ico
===================================================================
(Binary files differ)


Property changes on: 3.x/examples/cms/www/favicon.ico
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: 3.x/examples/cms/www/index.php
===================================================================
--- 3.x/examples/cms/www/index.php	                        (rev 0)
+++ 3.x/examples/cms/www/index.php	2007-08-28 14:21:06 UTC (rev 6240)
@@ -0,0 +1,8 @@
+<?php
+require_once(dirname(__FILE__) . '/../setup.php');
+require_once('limb/cms/src/lmbCmsApplication.class.php');
+
+$application = new lmbCmsApplication();
+$application->process();
+
+?>



More information about the limb-svn mailing list