diff options
28 files changed, 570 insertions, 1307 deletions
| diff --git a/.gitattributes b/.gitattributes index 289f27a2..c12fa6b2 100644 --- a/.gitattributes +++ b/.gitattributes @@ -356,8 +356,6 @@ buildscripts/index/api_index.php -text  buildscripts/index/build.php -text  buildscripts/index/quickstart_index.php -text  buildscripts/index/search.php -text -buildscripts/jsbuilder/build.php -text -buildscripts/jsbuilder/jsmin.php -text  buildscripts/phing/CREDITS -text  buildscripts/phing/LICENSE -text  buildscripts/phing/README -text @@ -2792,6 +2790,7 @@ tests/simple_unit/TableGateway/CountTest.php -text  tests/simple_unit/TableGateway/DeleteByPkTest.php -text  tests/simple_unit/TableGateway/MagicCallTest.php -text  tests/simple_unit/TableGateway/TableGatewayPgsqlTest.php -text +tests/simple_unit/TableGateway/TableInfoGatewayTest.php -text  tests/simple_unit/TableGateway/TestFindByPk.php -text  tests/simple_unit/application.xml -text  tests/simple_unit/unit.php -text @@ -1,6 +1,5 @@  /.project  /assets -buildscripts/jsbuilder/JSDoc  demos/quickstart/assets/274d44dc  demos/quickstart/assets/56624407  demos/quickstart/assets/587c9c16 @@ -9,10 +9,11 @@  <project name="prado" basedir="." default="help">    <taskdef name="prado-version-check" classname="PradoVersionTask" classpath="buildscripts/phing/tasks"/>    <taskdef name="prado-doc" classname="PradoDocTask" classpath="buildscripts/phing/tasks"/> -  <taskdef name="prado-pear" classname="PradoPearTask" classpath="buildscripts/phing/tasks"/> +<!--  <taskdef name="prado-pear" classname="PradoPearTask" classpath="buildscripts/phing/tasks"/>-->    <taskdef name="prado-quickstart-index" classname="QuickstartIndexTask" classpath="buildscripts/phing/tasks"/>    <taskdef name="prado-api-index" classname="ManualIndexTask" classpath="buildscripts/phing/tasks"/> -  <taskdef name="prado-test" classname="PradoTestTask" classpath="buildscripts/phing/tasks"/> +<!--  <taskdef name="prado-test" classname="PradoTestTask" classpath="buildscripts/phing/tasks"/>-->
 +  <taskdef name="compact-package" classname="PradoPackageTask" classpath="buildscripts/phing/tasks"/>    <!-- generates ${prado.version} and ${prado.revision} -->    <prado-version-check /> @@ -36,7 +37,7 @@    <property name="build.test.dir" value="${build.base.dir}/test-reports"/>    <property name="build.coverage.dir" value="${build.base.dir}/code-coverage"/>    <property name="build.snapshot.dir" value="${build.base.dir}/snapshot"/>
 -  <property name="build.compact.dir" value="${build.base.dir}/compact/${pkgname}" />
 +  <property name="build.compact.dir" value="${build.base.dir}/${pkgname}/compact" />
    <!--        All Source Files in framework @@ -134,7 +135,6 @@      For all PRADO developers:      - test    : run unit tests (results are under /build/test-reports); -    - js      : generate Javascript distribution files;      For PRADO release manager:      - dist    : create release files; @@ -152,8 +152,8 @@    <target name="compact-collections" description="Collections">
      <mkdir dir="${build.compact.dir}" />
      <compact-package output="${build.compact.dir}/collections.php" strip="${compact-strip-comments}">
 -      <filelist dir="framework" files="PradoBase.php,TComponent.php,Exceptions/TException.php" />
 -      <filelist dir="framework/Collections" files="TList.php,TMap.php,TAttributeCollection.php" />
 +      <filelist dir="framework" files="PradoBase.php,TComponent.php,Exceptions/TException.php,interfaces.php" />
 +      <filelist dir="framework/Collections" files="TList.php,TMap.php,TAttributeCollection.php,TPagedList.php,TPagedDataSource.php" />
      </compact-package>
      <delete file="${build.compact.dir}/messages.txt" />
      <copy file="framework/Exceptions/messages.txt" tofile="${build.compact.dir}/messages.txt" />
 @@ -220,9 +220,25 @@        destfile="${build.compact.dir}/messages.txt" />
    </target> +  <target name="compact-sqlmap" description="Package Active Record" depends="compact-db-all">
 +    <compact-package output="${build.compact.dir}/sqlmap.php" strip="${compact-strip-comments}">
 +      <filelist dir="framework/Data/SqlMap" files="TSqlMapManager.php,TSqlMapGateway.php" />
 +      <filelist dir="framework/Data/SqlMap/DataMapper"
 +        files="TSqlMapException.php,TSqlMapTypeHandlerRegistry.php,TSqlMapCache.php,TPropertyAccess.php,TLazyLoadList.php,TSqlMapPagedList.php"/>
 +      <filelist dir="framework/Data/SqlMap/Configuration"
 +        files="TSqlMapStatement.php,TDiscriminator.php,TInlineParameterMapParser.php,TParameterMap.php,TParameterProperty.php,TResultMap.php,TResultProperty.php,TSimpleDynamicParser.php,TSqlMapCacheModel.php,TSqlMapXmlConfiguration.php" />
 +      <filelist dir="framework/Data/SqlMap/Statements"
 +        files="IMappedStatement.php,TMappedStatement.php,TCachingStatement.php,TUpdateMappedStatement.php,TDeleteMappedStatement.php,TInsertMappedStatement.php,TPreparedCommand.php,TPreparedStatement.php,TPreparedStatementFactory.php,TSelectMappedStatement.php,TSimpleDynamicSql.php,TStaticSql.php"/>
 +    </compact-package>
 +    <append file="framework/Data/SqlMap/DataMapper/messages.txt"
 +      destfile="${build.compact.dir}/messages.txt" />
 +  </target>
 +
 +  <target name="compact-all" description="All packages" depends="compact-active-record,compact-sqlmap" />
 +
  <!-- end compact packaging -->
 -  <target name="build" depends="js" description="Building standard PRADO package v${prado.version}.${prado.revision}"> +  <target name="build" description="Building standard PRADO package v${prado.version}.${prado.revision}">      <echo>Building pradolite.php...</echo>      <delete file="framework/pradolite.php"/>      <exec command="${php} build.php" dir="buildscripts/phpbuilder" passthru="true"/> @@ -234,7 +250,7 @@        <fileset refid="framework"/>        <fileset refid="misc"/>
  	  <fileset refid="test-tools" /> -    </copy>  +    </copy>      <copy file="buildscripts/classtree/DWExtensionReadme.txt" tofile="${build.src.dir}/editors/Dreamweaver/readme.txt" />      <copy file="framework/pradolite.php" tofile="${build.src.dir}/framework/pradolite.php" /> @@ -290,7 +306,7 @@  	<echo>Generating CHM Content (Quickstart + ClassDocs)</echo>  	<exec command="${php} build.php" dir="buildscripts/chmbuilder" passthru="true"/> -	<!-- done on project website  +	<!-- done on project website  	<echo>Generating CHM Content (WIKI)</echo>  	<exec command="${php} build.php" dir="buildscripts/wikibuilder" passthru="true"/>  	--> @@ -366,11 +382,6 @@ the PRADO distribution:      </echo>    </target> -  <target name="js" description="Compiling Javascript distribution files"> -    <delete file="framework/Web/Javascripts/js/*.js" /> -    <exec command="${php} build.php" dir="buildscripts/jsbuilder" passthru="true"/> -  </target> -    <target name="test" description="Running unit tests">      <delete dir="${build.test.dir}"/>      <mkdir dir="${build.test.dir}"/> @@ -425,7 +436,7 @@ the PRADO distribution:      <mkdir dir="${reports.dir}"/>      <delete dir="${reports.unit.dir}"/>      <delete dir="${reports.codecoverage.dir}"/> -  +      <if>        <equals arg1="${codecoverage}" arg2="true"/>        <then> diff --git a/buildscripts/jsbuilder/build.php b/buildscripts/jsbuilder/build.php deleted file mode 100644 index ead55ae2..00000000 --- a/buildscripts/jsbuilder/build.php +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/php
 -<?php
 -/**
 - * Javascript build file.
 - *
 - * This script compresses a list of javascript source files
 - * and merges them into a few for redistribution.
 - *
 - * By default, all libraries will be built.
 - * You may, however, specify one or several to be built (to save time during development).
 - * To do so, pass the library names (without .js) as command line arguments.
 - * For example: php build.php base dom
 - *
 - * @author Xiang Wei Zhuo <weizhuo@gmail.com>, Qiang Xue <qiang.xue@gmail.com>
 - * @link http://www.pradosoft.com/
 - * @copyright Copyright © 2005 PradoSoft
 - * @license http://www.pradosoft.com/license/
 - * @version $Id$
 - * @package Tools
 - */
 -
 -/**
 - * The root directory for storing all source js files
 - */
 -define('SOURCE_DIR',realpath(dirname(__FILE__).'/../../framework/Web/Javascripts/source'));
 -/**
 - * The directory for storing compressed js files
 - */
 -define('TARGET_DIR',realpath(dirname(__FILE__).'/../../framework/Web/Javascripts/js'));
 -
 -define('JSMIN_AS_LIB',true);
 -
 -include(dirname(__FILE__).'/jsmin.php');
 -
 -if(SOURCE_DIR===false || TARGET_DIR===false)
 -	die('Unable to determine the build path.');
 -if(!is_writable(TARGET_DIR))
 -	die('Unable to create files under '.TARGET_DIR.'.');
 -
 -/**
 - * list of js library files to be compressed and built
 - */
 -$libraries = array(
 -	'prado.js' => array(
 -		'prototype/prototype.js',
 -		'scriptaculous/builder.js',
 -		'prado/prado.js',
 -		'prado/scriptaculous-adapter.js',
 -		'prado/controls/controls.js',
 -		'prado/ratings/ratings.js',
 -	),
 -
 -	'effects.js' => array(
 -		'scriptaculous/effects.js'
 -	),
 -
 -	'logger.js' => array(
 -		'prado/logger/logger.js',
 -	),
 -
 -	'validator.js' => array(
 -		'prado/validator/validation3.js'
 -	),
 -
 -	'datepicker.js' => array(
 -		'prado/datepicker/datepicker.js'
 -	),
 -
 -	'colorpicker.js' => array(
 -		'prado/colorpicker/colorpicker.js'
 -	),
 -
 -	'ajax.js' => array(
 -		'scriptaculous/controls.js',
 -		'prado/activecontrols/json.js',
 -		'prado/activecontrols/ajax3.js',
 -		'prado/activecontrols/activecontrols3.js',
 -		'prado/activecontrols/inlineeditor.js',
 -		'prado/activeratings/ratings.js'
 -	)
 -);
 -
 -/**
 - * Collect specific libraries to be built from command line
 - */
 -$requestedLibs=array();
 -for($i=1;$i<$argc;++$i)
 -	$requestedLibs[]=$argv[$i].'.js';
 -
 -$builds = 0;
 -/**
 - * loop through all target files and build them one by one
 - */
 -foreach($libraries as $jsFile => $sourceFiles)
 -{
 -	if(!empty($requestedLibs) && !in_array($jsFile,$requestedLibs))
 -		continue;
 -	//$libFile=TARGET_DIR.'/'.$jsFile;
 -	echo "\nBuilding $jsFile...\n";
 -	$contents='';
 -	foreach($sourceFiles as $sourceJsFile)
 -	{
 -		$sourceFile=SOURCE_DIR.'/'.$sourceJsFile;
 -		if(!is_file($sourceFile))
 -			echo "Source file not found: $sourceFile\n";
 -
 -		echo "...adding $sourceJsFile\n";
 -		$contents.=file_get_contents($sourceFile)."\n\n";
 -	}
 -	$debugFile=TARGET_DIR.'/debug/'.$jsFile;
 -	$compressFile=TARGET_DIR.'/compressed/'.$jsFile;
 -	file_put_contents($debugFile,$contents);
 -	$jsMin = new JSMin($debugFile, $compressFile);
 -	$jsMin -> minify();
 -	unset($jsMin);
 -	//@unlink($tempFile);
 -	echo "Saving file {$jsFile}\n";
 -	$builds++;
 -}
 -
 -?>
\ No newline at end of file diff --git a/buildscripts/jsbuilder/jsmin.php b/buildscripts/jsbuilder/jsmin.php deleted file mode 100644 index bc63dd4e..00000000 --- a/buildscripts/jsbuilder/jsmin.php +++ /dev/null @@ -1,931 +0,0 @@ -<?php
 -/**
 -* JSMin_lib.php (for PHP 4, 5)
 -*
 -* PHP adaptation of JSMin, published by Douglas Crockford as jsmin.c, also based
 -* on its Java translation by John Reilly.
 -*
 -* Permission is hereby granted to use the PHP version under the same conditions
 -* as jsmin.c, which has the following notice :
 -*
 -* ----------------------------------------------------------------------------
 -*
 -* Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
 -*
 -* Permission is hereby granted, free of charge, to any person obtaining a copy of
 -* this software and associated documentation files (the "Software"), to deal in
 -* the Software without restriction, including without limitation the rights to
 -* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 -* of the Software, and to permit persons to whom the Software is furnished to do
 -* so, subject to the following conditions:
 -*
 -* The above copyright notice and this permission notice shall be included in all
 -* copies or substantial portions of the Software.
 -*
 -* The Software shall be used for Good, not Evil.
 -*
 -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 -* SOFTWARE.
 -*
 -* ----------------------------------------------------------------------------
 -*
 -* @copyright   No new copyright ; please keep above and following information.
 -* @author      David Holmes <dholmes@cfdsoftware.net> of CFD Labs, France
 -* @author      Gaetano Giunta
 -* @version     $Id: $
 -*
 -* Please note, this is a brutal and simple conversion : it could undoubtedly be
 -* improved, as a PHP implementation, by applying more PHP-specific programming
 -* features.
 -*
 -* Exceptions and all PHP 5 - only features ahve been removed for compat with PHP 4
 -*
 -* Note : whereas jsmin.c works specifically with the standard input and output
 -* streams, this implementation only falls back on them if file pathnames are
 -* not provided to the JSMin() constructor.
 -*
 -* Examples comparing with the application compiled from jsmin.c :
 -*
 -* jsmin < orig.js > mini.js        JSMin.php orig.js mini.js
 -*                                  JSMin.php orig.js > mini.js
 -*                                  JSMin.php - mini.js < orig.js
 -* jsmin < orig.js                  JSMin.php orig.js
 -*                                  JSMin.php orig.js -
 -* jsmin > mini.js                  JSMin.php - mini.js
 -*                                  JSMin.php > mini.js
 -* jsmin comm1 comm2 < a.js > b.js  JSMin.php a.js b.js comm1 comm2
 -*                                  JSMin.php a.js b.js -c comm1 comm2
 -*                                  JSMin.php a.js --comm comm1 comm2 > b.js
 -*                                  JSMin.php -c comm1 comm2 < a.js > b.js
 -* (etc...)
 -*
 -* See JSMin.php -h (or --help) for command-line documentation.
 -*
 -* NEW AND IMPROVED in version 0.2:
 -* to take advantage of this file in your own code, you can do the following:
 -*
 -* define('JSMIN_AS_LIB', true); // prevents auto-run on include
 -* include('jsmin.php');
 -* // the JSMin class now works on php strings, too
 -* $jsMin = new JSMin(file_get_contents('e:/htdocs/awstats_misc_tracker.js'), false);
 -* // in that case, the modifies string is returned by minify():
 -* $out = $jsMin->minify();
 -*
 -*/
 -
 -/**
 -* Version of this PHP translation.
 -*/
 -
 -define('JSMIN_VERSION', '0.2');
 -
 -/**
 -* How fgetc() reports an End Of File.
 -* N.B. : use === and not == to test the result of fgetc() ! (see manual)
 -*/
 -
 -define('EOF', FALSE);
 -
 -/**
 -* Some ASCII character ordinals.
 -* N.B. : PHP identifiers are case-insensitive !
 -*/
 -
 -define('ORD_NL', ord("\n"));
 -define('ORD_space', ord(' '));
 -define('ORD_cA', ord('A'));
 -define('ORD_cZ', ord('Z'));
 -define('ORD_a', ord('a'));
 -define('ORD_z', ord('z'));
 -define('ORD_0', ord('0'));
 -define('ORD_9', ord('9'));
 -
 -/**
 -* Generic exception class related to JSMin.
 -*/
 -/*
 -class JSMinException extends Exception {
 -}
 -*/
 -class JSMinException {
 -}
 -
 -/**
 -* A JSMin exception indicating that a file provided for input or output could not be properly opened.
 -*/
 -
 -class FileOpenFailedJSMinException extends JSMinException {
 -}
 -
 -/**
 -* A JSMin exception indicating that an unterminated comment was encountered in input.
 -*/
 -
 -class UnterminatedCommentJSMinException extends JSMinException {
 -}
 -
 -/**
 -* A JSMin exception indicatig that an unterminated string literal was encountered in input.
 -*/
 -
 -class UnterminatedStringLiteralJSMinException extends JSMinException {
 -}
 -
 -/**
 -* A JSMin exception indicatig that an unterminated regular expression lieteral was encountered in input.
 -*/
 -
 -class UnterminatedRegExpLiteralJSMinException extends JSMinException {
 -}
 -
 -/**
 - * Constant describing an {@link action()} : Output A. Copy B to A. Get the next B.
 - */
 -
 -define ('JSMIN_ACT_FULL', 1);
 -
 -/**
 - * Constant describing an {@link action()} : Copy B to A. Get the next B. (Delete A).
 - */
 -
 -define ('JSMIN_ACT_BUF', 2);
 -
 -/**
 - * Constant describing an {@link action()} : Get the next B. (Delete B).
 - */
 -
 -define ('JSMIN_ACT_IMM', 3);
 -
 -/**
 -* Main JSMin application class.
 -*
 -* Example of use :
 -*
 -* $jsMin = new JSMin(...input..., ...output...);
 -* $jsMin->minify();
 -*
 -* Do not specify input and/or output (or default to '-') to use stdin and/or stdout.
 -*/
 -
 -class JSMin {
 -
 -    /**
 -     * The input stream, from which to read a JS file to minimize. Obtained by fopen().
 -     * NB: might be a string instead of a stream
 -     * @var SplFileObject | string
 -     */
 -    var $in;
 -
 -    /**
 -     * The output stream, in which to write the minimized JS file. Obtained by fopen().
 -     * NB: might be a string instead of a stream
 -     * @var SplFileObject | string
 -     */
 -    var $out;
 -
 -    /**
 -     * Temporary I/O character (A).
 -     * @var string
 -     */
 -    var $theA;
 -
 -    /**
 -     * Temporary I/O character (B).
 -     * @var string
 -     */
 -    var $theB;
 -
 -	/** variables used for string-based parsing **/
 -	var $inLength = 0;
 -	var $inPos = 0;
 -	var $isString = false;
 -
 -    /**
 -     * Indicates whether a character is alphanumeric or _, $, \ or non-ASCII.
 -     *
 -     * @param   string      $c  The single character to test.
 -     * @return  boolean     Whether the char is a letter, digit, underscore, dollar, backslash, or non-ASCII.
 -     */
 -    function isAlphaNum($c) {
 -
 -        // Get ASCII value of character for C-like comparisons
 -
 -        $a = ord($c);
 -
 -        // Compare using defined character ordinals, or between PHP strings
 -        // Note : === is micro-faster than == when types are known to be the same
 -
 -        return
 -            ($a >= ORD_a && $a <= ORD_z) ||
 -            ($a >= ORD_0 && $a <= ORD_9) ||
 -            ($a >= ORD_cA && $a <= ORD_cZ) ||
 -            $c === '_' || $c === '$' || $c === '\\' || $a > 126
 -        ;
 -    }
 -
 -    /**
 -     * Get the next character from the input stream.
 -     *
 -     * If said character is a control character, translate it to a space or linefeed.
 -     *
 -     * @return  string      The next character from the specified input stream.
 -     * @see     $in
 -     * @see     peek()
 -     */
 -    function get() {
 -
 -        // Get next input character and advance position in file
 -//var_dump($this);
 -		if ($this->isString) {
 -			if ($this->inPos < $this->inLength) {
 -				$c = $this->in[$this->inPos];
 -				++$this->inPos;
 -			}
 -			else {
 -				return EOF;
 -			}
 -		}
 -		else
 -	        $c = $this->in->fgetc();
 -
 -        // Test for non-problematic characters
 -
 -        if ($c === "\n" || $c === EOF || ord($c) >= ORD_space) {
 -            return $c;
 -        }
 -
 -        // else
 -        // Make linefeeds into newlines
 -
 -        if ($c === "\r") {
 -            return "\n";
 -        }
 -
 -        // else
 -        // Consider space
 -
 -        return ' ';
 -    }
 -
 -    /**
 -     * Get the next character from the input stream, without gettng it.
 -     *
 -     * @return  string      The next character from the specified input stream, without advancing the position
 -     *                      in the underlying file.
 -     * @see     $in
 -     * @see     get()
 -     */
 -    function peek() {
 -
 -		if ($this->isString) {
 -			if ($this->inPos < $this->inLength) {
 -				$c = $this->in[$this->inPos];
 -			}
 -			else {
 -				return EOF;
 -			}
 -		}
 -		else {
 -	        // Get next input character
 -
 -	        $c = $this->in->fgetc();
 -
 -	        // Regress position in file
 -
 -	        $this->in->fseek(-1, SEEK_CUR);
 -
 -	        // Return character obtained
 -	    }
 -
 -        return $c;
 -    }
 -
 -	/**
 -	 * Adds a char to the output steram / string
 -	 * @see $out
 -	 */
 -	function put($c)
 -	{
 -		if ($this->isString) {
 -			$this->out .= $c;
 -		}
 -		else {
 -			$this->out->fwrite($c);
 -		}
 -	}
 -
 -    /**
 -     * Get the next character from the input stream, excluding comments.
 -     *
 -     * {@link peek()} is used to see if a '/' is followed by a '*' or '/'.
 -     * Multiline comments are actually returned as a single space.
 -     *
 -     * @return  string  The next character from the specified input stream, skipping comments.
 -     * @see     $in
 -     */
 -    function next() {
 -
 -        // Get next char from input, translated if necessary
 -
 -        $c = $this->get();
 -
 -        // Check comment possibility
 -
 -        if ($c == '/') {
 -
 -            // Look ahead : a comment is two slashes or slashes followed by asterisk (to be closed)
 -
 -            switch ($this->peek()) {
 -
 -                case '/' :
 -
 -                    // Comment is up to the end of the line
 -                    // TOTEST : simple $this->in->fgets()
 -
 -                    while (true) {
 -
 -                        $c = $this->get();
 -
 -                        if (ord($c) <= ORD_NL) {
 -                            return $c;
 -                        }
 -                    }
 -
 -                case '*' :
 -
 -                    // Comment is up to comment close.
 -                    // Might not be terminated, if we hit the end of file.
 -
 -                    while (true) {
 -
 -                        // N.B. not using switch() because of having to test EOF with ===
 -
 -                        $c = $this->get();
 -
 -                        if ($c == '*') {
 -
 -                            // Comment termination if the char ahead is a slash
 -
 -                            if ($this->peek() == '/') {
 -
 -                                // Advance again and make into a single space
 -
 -                                $this->get();
 -                                return ' ';
 -                            }
 -                        }
 -                        else if ($c === EOF) {
 -
 -                            // Whoopsie
 -
 -                            //throw new UnterminatedCommentJSMinException();
 -                            trigger_error('UnterminatedComment', E_USER_ERROR);
 -                        }
 -                    }
 -
 -                default :
 -
 -                    // Not a comment after all
 -
 -                    return $c;
 -            }
 -        }
 -
 -        // No risk of a comment
 -
 -        return $c;
 -    }
 -
 -    /**
 -     * Do something !
 -     *
 -     * The action to perform is determined by the argument :
 -     *
 -     * JSMin::ACT_FULL : Output A. Copy B to A. Get the next B.
 -     * JSMin::ACT_BUF  : Copy B to A. Get the next B. (Delete A).
 -     * JSMin::ACT_IMM  : Get the next B. (Delete B).
 -     *
 -     * A string is treated as a single character. Also, regular expressions are recognized if preceded
 -     * by '(', ',' or '='.
 -     *
 -     * @param   int     $action     The action to perform : one of the JSMin::ACT_* constants.
 -     */
 -    function action($action) {
 -
 -        // Choice of possible actions
 -        // Note the frequent fallthroughs : the actions are decrementally "long"
 -
 -        switch ($action) {
 -
 -            case JSMIN_ACT_FULL :
 -
 -                // Write A to output, then fall through
 -
 -                $this->put($this->theA);
 -
 -            case JSMIN_ACT_BUF : // N.B. possible fallthrough from above
 -
 -                // Copy B to A
 -
 -                $tmpA = $this->theA = $this->theB;
 -
 -                // Treating a string as a single char : outputting it whole
 -                // Note that the string-opening char (" or ') is memorized in B
 -
 -                if ($tmpA == '\'' || $tmpA == '"') {
 -
 -                    while (true) {
 -
 -                        // Output string contents
 -
 -                        $this->put($tmpA);
 -
 -                        // Get next character, watching out for termination of the current string,
 -                        // new line & co (then the string is not terminated !), or a backslash
 -                        // (upon which the following char is directly output to serve the escape mechanism)
 -
 -                        $tmpA = $this->theA = $this->get();
 -
 -                        if ($tmpA == $this->theB) {
 -
 -                            // String terminated
 -
 -                            break; // from while(true)
 -                        }
 -
 -                        // else
 -
 -                        if (ord($tmpA) <= ORD_NL) {
 -
 -                            // Whoopsie
 -
 -                            //throw new UnterminatedStringLiteralJSMinException();
 -                            trigger_error('UnterminatedStringLiteral', E_USER_ERROR);
 -                        }
 -
 -                        // else
 -
 -                        if ($tmpA == '\\') {
 -
 -                            // Escape next char immediately
 -
 -                            $this->put($tmpA);
 -                            $tmpA = $this->theA = $this->get();
 -                        }
 -                    }
 -                }
 -
 -            case JSMIN_ACT_IMM : // N.B. possible fallthrough from above
 -
 -                // Get the next B
 -
 -                $this->theB = $this->next();
 -
 -                // Special case of recognising regular expressions (beginning with /) that are
 -                // preceded by '(', ',' or '='
 -
 -                $tmpA = $this->theA;
 -
 -                if ($this->theB == '/' && ($tmpA == '(' || $tmpA == ',' || $tmpA == '=')) {
 -
 -                    // Output the two successive chars
 -
 -                    $this->put($tmpA);
 -                    $this->put($this->theB);
 -
 -                    // Look for the end of the RE literal, watching out for escaped chars or a control /
 -                    // end of line char (the RE literal then being unterminated !)
 -
 -                    while (true) {
 -
 -                        $tmpA = $this->theA = $this->get();
 -
 -                        if ($tmpA == '/') {
 -
 -                            // RE literal terminated
 -
 -                            break; // from while(true)
 -                        }
 -
 -                        // else
 -
 -                        if ($tmpA == '\\') {
 -
 -                            // Escape next char immediately
 -
 -                            $this->put($tmpA);
 -                            $tmpA = $this->theA = $this->get();
 -                        }
 -                        else if (ord($tmpA) <= ORD_NL) {
 -
 -                            // Whoopsie
 -
 -                            //throw new UnterminatedRegExpLiteralJSMinException();
 -                            trigger_error('UnterminatedRegExpLiteral', E_USER_ERROR);
 -                        }
 -
 -                        // Output RE characters
 -
 -                        $this->put($tmpA);
 -                    }
 -
 -                    // Move forward after the RE literal
 -
 -                    $this->theB = $this->next();
 -                }
 -
 -            break;
 -            default :
 -				//throw new JSMinException('Expected a JSMin::ACT_* constant in action().');
 -				trigger_error('Expected a JSMin::ACT_* constant in action()', E_USER_ERROR);
 -        }
 -    }
 -
 -    /**
 -     * Run the JSMin application : minify some JS code.
 -     *
 -     * The code is read from the input stream, and its minified version is written to the output one.
 -     * In case input is a string, minified vesrions is also returned by this function as string.
 -     * That is : characters which are insignificant to JavaScript are removed, as well as comments ;
 -     * tabs are replaced with spaces ; carriage returns are replaced with linefeeds, and finally most
 -     * spaces and linefeeds are deleted.
 -     *
 -     * Note : name was changed from jsmin() because PHP identifiers are case-insensitive, and it is already
 -     * the name of this class.
 -     *
 -     * @see     JSMin()
 -     * @return null | string
 -     */
 -    function minify() {
 -
 -        // Initialize A and run the first (minimal) action
 -
 -        $this->theA = "\n";
 -        $this->action(JSMIN_ACT_IMM);
 -
 -        // Proceed all the way to the end of the input file
 -
 -        while ($this->theA !== EOF) {
 -
 -            switch ($this->theA) {
 -
 -                case ' ' :
 -
 -                    if (JSMin::isAlphaNum($this->theB)) {
 -                        $this->action(JSMIN_ACT_FULL);
 -                    }
 -                    else {
 -                        $this->action(JSMIN_ACT_BUF);
 -                    }
 -
 -                break;
 -                case "\n" :
 -
 -                    switch ($this->theB) {
 -
 -                        case '{' : case '[' : case '(' :
 -                        case '+' : case '-' :
 -
 -                            $this->action(JSMIN_ACT_FULL);
 -
 -                        break;
 -                        case ' ' :
 -
 -                            $this->action(JSMIN_ACT_IMM);
 -
 -                        break;
 -                        default :
 -
 -                            if (JSMin::isAlphaNum($this->theB)) {
 -                                $this->action(JSMIN_ACT_FULL);
 -                            }
 -                            else {
 -                                $this->action(JSMIN_ACT_BUF);
 -                            }
 -
 -                        break;
 -                    }
 -
 -                break;
 -                default :
 -
 -                    switch ($this->theB) {
 -
 -                        case ' ' :
 -
 -                            if (JSMin::isAlphaNum($this->theA)) {
 -
 -                                $this->action(JSMIN_ACT_FULL);
 -                                break;
 -                            }
 -
 -                            // else
 -
 -                            $this->action(JSMIN_ACT_IMM);
 -
 -                        break;
 -                        case "\n" :
 -
 -                            switch ($this->theA) {
 -
 -                                case '}' : case ']' : case ')' : case '+' :
 -                                case '-' : case '"' : case '\'' :
 -
 -                                    $this->action(JSMIN_ACT_FULL);
 -
 -                                break;
 -                                default :
 -
 -                                    if (JSMin::isAlphaNum($this->theA)) {
 -                                        $this->action(JSMIN_ACT_FULL);
 -                                    }
 -                                    else {
 -                                        $this->action(JSMIN_ACT_IMM);
 -                                    }
 -
 -                                break;
 -                            }
 -
 -                        break;
 -                        default :
 -
 -                            $this->action(JSMIN_ACT_FULL);
 -
 -                        break;
 -                    }
 -
 -                break;
 -            }
 -        }
 -
 -	    if ($this->isString) {
 -		    return $this->out;
 -
 -	    }
 -    }
 -
 -    /**
 -     * Prepare a new JSMin application.
 -     *
 -     * The next step is to {@link minify()} the input into the output.
 -     *
 -     * @param   string  $inFileName     The pathname of the input (unminified JS) file. STDIN if '-' or absent.
 -     * @param   string  $outFileName    The pathname of the output (minified JS) file. STDOUT if '-' or absent.
 -     *                                  If outFileName === FALSE, we assume that inFileName is in fact the string to be minified!!!
 -     * @param   array   $comments       Optional lines to present as comments at the beginning of the output.
 -     */
 -	function JSMin($inFileName = '-', $outFileName = '-', $comments = NULL) {
 -		if ($outFileName === FALSE) {
 -			$this->JSMin_String($inFileName, $comments);
 -		}
 -		else {
 -			$this->JSMin_File($inFileName, $outFileName, $comments);
 -		}
 -	}
 -
 -    function JSMin_File($inFileName = '-', $outFileName = '-', $comments = NULL) {
 -
 -        // Recuperate input and output streams.
 -        // Use STDIN and STDOUT by default, if they are defined (CLI mode) and no file names are provided
 -
 -            if ($inFileName == '-')  $inFileName  = 'php://stdin';
 -            if ($outFileName == '-') $outFileName = 'php://stdout';
 -
 -            try {
 -
 -                $this->in = new SplFileObject($inFileName, 'rb', TRUE);
 -            }
 -            catch (Exception $e) {
 -
 -                throw new FileOpenFailedJSMinException(
 -                    'Failed to open "'.$inFileName.'" for reading only.'
 -                );
 -            }
 -
 -            try {
 -
 -                $this->out = new SplFileObject($outFileName, 'wb', TRUE);
 -            }
 -            catch (Exception $e) {
 -
 -                throw new FileOpenFailedJSMinException(
 -                    'Failed to open "'.$outFileName.'" for writing only.'
 -                );
 -            }
 -
 -			/*$this->in = fopen($inFileName, 'rb');
 -			if (!$this->in) {
 -				trigger_error('Failed to open "'.$inFileName, E_USER_ERROR);
 -			}
 -			$this->out = fopen($outFileName, 'wb');
 -			if (!$this->out) {
 -				trigger_error('Failed to open "'.$outFileName, E_USER_ERROR);
 -			}*/
 -
 -            // Present possible initial comments
 -
 -            if ($comments !== NULL) {
 -                foreach ($comments as $comm) {
 -                    $this->out->fwrite('// '.str_replace("\n", " ", $comm)."\n");
 -                }
 -            }
 -
 -    }
 -
 -    function JSMin_String($inString, $comments = NULL) {
 -        $this->in = $inString;
 -        $this->out = '';
 -		$this->inLength = strlen($inString);
 -		$this->inPos = 0;
 -		$this->isString = true;
 -
 -        if ($comments !== NULL) {
 -            foreach ($comments as $comm) {
 -                $this->out .= '// '.str_replace("\n", " ", $comm)."\n";
 -            }
 -        }
 -	}
 -}
 -
 -//
 -// OTHER FUNCTIONS
 -//
 -
 -/**
 -* Displays inline help for the application.
 -*/
 -
 -function printHelp() {
 -
 -    // All the inline help
 -
 -    echo "\n";
 -    echo "Usage : JSMin.php [inputFile] [outputFile] [[-c] comm1 comm2 ...]\n";
 -    echo "        JSMin.php [-v|-h]\n";
 -    echo "\n";
 -    echo "Minify JavaScript code using JSMin, the JavaScript Minifier.\n";
 -    echo "\n";
 -    echo "JSMin is a filter which removes comments and unnecessary whitespace\n";
 -    echo "from a script read in the inputFile (stdin by default), as well as\n";
 -    echo "omitting or modifying some characters, before writing the results to\n";
 -    echo "the outputFile (stdout by default).\n";
 -    echo "It does not change the behaviour of the program that is minifies.\n";
 -    echo "The result may be harder to debug. It will definitely be harder to\n";
 -    echo "read. It typically reduces filesize by half, resulting in faster\n";
 -    echo "downloads. It also encourages a more expressive programming style\n";
 -    echo "because it eliminates the download cost of clean, literate self-\n";
 -    echo "documentation.\n";
 -    echo "\n";
 -    echo "The '-' character can be used to explicitely specify a standard\n";
 -    echo "stream for input or output.\n";
 -    echo "\n";
 -    echo "With the optional -c (--comm) option, all following parameters will\n";
 -    echo "be listed at the beginning of the output as comments. This is a\n";
 -    echo "convenient way of replacing copyright messages and other info. The\n";
 -    echo "option is unnecessary if an input and output file are specified :\n";
 -    echo "following parameters will then automatically be treated thus.\n";
 -    echo "\n";
 -    echo "Options :\n";
 -    echo "\n";
 -    echo "  -c, --comm      Present following parameters as initial comments.\n";
 -    echo "  -h, --help      Display this information.\n";
 -    echo "  -v, --version   Display short version information.\n";
 -    echo "\n";
 -    echo "The JavaScript Minifier is copyright (c) 2002 by Douglas Crockford\n";
 -    echo "and available online at http://javascript.crockford.com/jsmin.html.\n";
 -    echo "This PHP translation is by David Holmes of CFD Labs, France, 2006.\n";
 -    echo "\n";
 -}
 -
 -/**
 -* Displays version information for the application.
 -*/
 -
 -function printVersion() {
 -
 -    // Minimum info
 -
 -    echo "JSMin, the JavaScript Minifier, copyright (c) 2002 by Douglas Crockford.\n";
 -    echo "PHP translation version ".JSMIN_VERSION." by David Holmes, CFD Labs.\n";
 -}
 -
 -//
 -// ENTRY POINT
 -//
 -
 -// Allow user to include this file without having it run atomatically, ie. as if it was a lib
 -if (!defined('JSMIN_AS_LIB')) {
 -
 -define('EXIT_SUCCESS', 0);
 -define('EXIT_FAILURE', 1);
 -
 -// Examine command-line parameters
 -// First shift off the first parameter, the executable's name
 -
 -if (!isset($argv)) {
 -	die("Please run this utility from a command line, or set php.ini setting 'register_argc_argv' to true.\nTo use this file in your own code, define 'JSMIN_AS_LIB' before inclusion.");
 -}
 -
 -array_shift($argv);
 -
 -$inFileName = NULL;
 -$outFileName = NULL;
 -
 -$haveCommentParams = FALSE;
 -$comments = array();
 -
 -foreach ($argv as $arg) {
 -
 -    // Bypass the rest if we are now considering initial comments
 -
 -    if ($haveCommentParams) {
 -
 -        $comments[] = $arg;
 -        continue;
 -    }
 -
 -    // else
 -    // Look for an option (length > 1 because of '-' for indicating stdin or
 -    // stdout)
 -
 -    if ($arg[0] == '-' && strlen($arg) > 1) {
 -
 -        switch ($arg) {
 -
 -            case '-c' : case '--comm' :
 -
 -                // Following parameters will be initial comments
 -
 -                $haveCommentParams = TRUE;
 -
 -            break;
 -            case '-h' : case '--help' :
 -
 -                // Display inline help and exit normally
 -
 -                printHelp();
 -                exit(EXIT_SUCCESS);
 -
 -            case '-v' : case '--version' :
 -
 -                // Display short version information and exit normally
 -
 -                printVersion();
 -                exit(EXIT_SUCCESS);
 -
 -            default :
 -
 -                // Reject any other (unknown) option
 -
 -                echo "\n";
 -                echo "ERROR : unknown option \"$arg\", sorry.\n";
 -
 -                printHelp();
 -                exit(EXIT_FAILURE);
 -        }
 -
 -        continue;
 -    }
 -
 -    // else
 -    // At this point, parameter is neither to be considered as an initial
 -    // comment, nor is it an option. It is an input or output file.
 -
 -    if ($inFileName === NULL) {
 -
 -        // No input file yet, this is it
 -
 -        $inFileName = $arg;
 -    }
 -    else if ($outFileName === NULL) {
 -
 -        // An input file but no output file yet, this is it
 -
 -        $outFileName = $arg;
 -    }
 -    else {
 -
 -        // Already have input and output file, this is a first initial comment
 -
 -        $haveCommentParams = TRUE;
 -        $comments[] = $arg;
 -    }
 -}
 -
 -if ($inFileName === NULL)  $inFileName  = '-';
 -if ($outFileName === NULL) $outFileName = '-';
 -
 -// Prepare and run the JSMin application
 -// If pathnames are not provided or '-', standard input/output streams are used
 -
 -$jsMin = new JSMin($inFileName, $outFileName, $comments);
 -$jsMin->minify();
 -
 -}
 -
 -?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoPackageTask.php b/buildscripts/phing/tasks/PradoPackageTask.php index fefeb1e0..8784bb77 100644 --- a/buildscripts/phing/tasks/PradoPackageTask.php +++ b/buildscripts/phing/tasks/PradoPackageTask.php @@ -57,6 +57,9 @@ class PradoPackageTask extends Task  		$content = preg_replace('/^\s*Prado::trace.*\s*;\s*$/mu','',$content);
  		$content = preg_replace('/(PradoBase::using|Prado::using|require_once|include_once)\s*\(.*?\);/mu','',$content);
  		$content = str_replace('Prado::', 'PradoBase::', $content);
 +		$content = str_replace('PradoBase::getApplication()->getMode()', 'true', $content);
 +		$content = str_replace('TApplicationMode::Debug', 'true', $content);
 +		$content = str_replace('/Exceptions/messages', '/messages', $content);
  		if($this->strip)
  			$content=$this->strip_comments($content);
  		$content=$this->strip_empty_lines($content);
 diff --git a/framework/3rdParty/geshi/geshi/prado.php b/framework/3rdParty/geshi/geshi/prado.php index c9d96a35..ba2791f7 100644 --- a/framework/3rdParty/geshi/geshi/prado.php +++ b/framework/3rdParty/geshi/geshi/prado.php @@ -140,7 +140,7 @@ $language_data = array (  			'<![CDATA[' => ']]>'  			),  		3 => array( -			'<' => '>' +			'<' => '/>'  			)  	),  	'HIGHLIGHT_STRICT_BLOCK' => array( diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php index 0400661d..1ea06a60 100644 --- a/framework/Data/ActiveRecord/TActiveRecord.php +++ b/framework/Data/ActiveRecord/TActiveRecord.php @@ -17,7 +17,10 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordCriteria');   * Base class for active records.   *   * An active record creates an object that wraps a row in a database table - * or view, encapsulates the database access, and adds domain logic on that data. + * or view, encapsulates the database access, and adds domain logic on that data.
 + *
 + * Active record objects are stateful, this is main difference between the
 + * TActiveRecord implementation and the TTableGateway implementation.   *   * The essence of an Active Record is an object model of the   * domain (e.g. products, items) that incorporates both behavior and @@ -140,7 +143,11 @@ abstract class TActiveRecord extends TComponent  	}  	/** -	 * Returns the instance of a active record finder for a particular class. +	 * Returns the instance of a active record finder for a particular class.
 +	 * The finder objects are static instances for each ActiveRecord class.
 +	 * This means that event handlers bound to these finder instances are class wide.
 +	 * Create a new instance of the ActiveRecord class if you wish to bound the
 +	 * event handlers to object instance.  	 * @param string active record class name.  	 * @return TActiveRecord active record finder instance.  	 * @throws TActiveRecordException if class name equals 'TActiveRecord'. @@ -168,6 +175,14 @@ abstract class TActiveRecord extends TComponent  	public function getRecordManager()  	{  		return TActiveRecordManager::getInstance(); +	}
 +
 +	/**
 +	 * @return TActiveRecordGateway record table gateway.
 +	 */
 +	public function getRecordGateway()
 +	{
 +		return $this->getRecordManager()->getRecordGateway();
  	}  	/** @@ -266,15 +281,20 @@ abstract class TActiveRecord extends TComponent  		//try the cache (the cache object must be clean)  		if(!is_null($obj = $registry->getCachedInstance($data))) -			return $obj; +			return $obj;
 +
 +		$gateway = $this->getRecordManager()->getRecordGateway();
  		//create and populate the object  		$obj = Prado::createComponent($type); -		foreach($data as $name => $value) -			$obj->{$name} = $value; +		$tableInfo = $gateway->getRecordTableInfo($obj);
 +		foreach($tableInfo->getColumns()->getKeys() as $name)
 +		{
 +			if(isset($data[$name]))
 +				$obj->{$name} = $data[$name]; +		} -		$gateway = $this->getRecordManager()->getRecordGateway(); -		$obj->_readOnly = $gateway->getRecordTableInfo($this)->getIsView(); +		$obj->_readOnly = $tableInfo->getIsView();  		//cache it  		return $registry->addCachedInstance($data,$obj); @@ -484,21 +504,38 @@ abstract class TActiveRecord extends TComponent  		else  			throw new TActiveRecordException('ar_invalid_criteria');  	} +
 +	/**
 +	 * Raised when a command is prepared and parameter binding is completed.
 +	 * The parameter object is TDataGatewayEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getCommand Command} property can be
 +	 * inspected to obtain the sql query to be executed.
 +	 *
 +	 * Note well that the finder objects obtained from ActiveRecord::finder()
 +	 * method are static objects. This means that the event handlers are
 +	 * bound to a static finder object and not to each distinct active record object.
 +	 * @param TDataGatewayEventParameter
 +	 */
 +	public function onCreateCommand($param)
 +	{
 +		$this->raiseEvent('OnCreateCommand', $this, $param);
 +	}
 +
 +	/**
 +	 * Raised when a command is executed and the result from the database was returned.
 +	 * The parameter object is TDataGatewayResultEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getResult Result} property contains
 +	 * the data return from the database. The data returned can be changed
 +	 * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
 +	 *
 +	 * Note well that the finder objects obtained from ActiveRecord::finder()
 +	 * method are static objects. This means that the event handlers are
 +	 * bound to a static finder object and not to each distinct active record object.
 +	 * @param TDataGatewayResultEventParameter
 +	 */
 +	public function onExecuteCommand($param)
 +	{
 +		$this->raiseEvent('OnExecuteCommand', $this, $param);
 +	}
  } - -/** - * TActiveRecordEventParameter class. - * - * @author Wei Zhuo <weizho[at]gmail[dot]com> - * @version $Id$ - * @package System.Data.ActiveRecord - * @since 3.1 - */ -class TActiveRecordEventParameter extends TEventParameter -{ - -} - - -  ?> diff --git a/framework/Data/ActiveRecord/TActiveRecordCriteria.php b/framework/Data/ActiveRecord/TActiveRecordCriteria.php index cc4da7c8..8328b4a6 100644 --- a/framework/Data/ActiveRecord/TActiveRecordCriteria.php +++ b/framework/Data/ActiveRecord/TActiveRecordCriteria.php @@ -34,29 +34,7 @@ Prado::using('System.Data.DataGateway.TSqlCriteria');   */
  class TActiveRecordCriteria extends TSqlCriteria
  {
 -	/**
 -	 * This method is invoked before the object is deleted from the database.
 -	 * The method raises 'OnDelete' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onDelete($param)
 -	{
 -		$this->raiseEvent('OnDelete', $this, $param);
 -	}
 -	/**
 -	 * This method is invoked before any select query is executed on the database.
 -	 * The method raises 'OnSelect' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onSelect($param)
 -	{
 -		$this->raiseEvent('OnSelect', $this, $param);
 -	}
  }
  ?>
\ No newline at end of file diff --git a/framework/Data/ActiveRecord/TActiveRecordGateway.php b/framework/Data/ActiveRecord/TActiveRecordGateway.php index 9c480ad0..c3239c5c 100644 --- a/framework/Data/ActiveRecord/TActiveRecordGateway.php +++ b/framework/Data/ActiveRecord/TActiveRecordGateway.php @@ -1,6 +1,6 @@  <?php  /**
 - * TActiveRecordGateway, TActiveRecordStatementType, TActiveRecordGatewayEventParameter classes file.
 + * TActiveRecordGateway, TActiveRecordStatementType, TActiveRecordEventParameter classes file.
   *
   * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
   * @link http://www.pradosoft.com/
 @@ -25,6 +25,8 @@ class TActiveRecordGateway extends TComponent  	private $_tables=array(); //table cache
  	private $_meta=array(); //meta data cache.
  	private $_commandBuilders=array();
 +	private $_currentRecord;
 +
  	/**
  	 * Constant name for specifying optional table name in TActiveRecord.
  	 */
 @@ -99,7 +101,7 @@ class TActiveRecordGateway extends TComponent  				if(!isset($this->_meta[$connStr]))
  				{
  					Prado::using('System.Data.Common.TDbMetaData');
 -					$this->_meta[$connStr] = TDbMetaData::getMetaData($connection);
 +					$this->_meta[$connStr] = TDbMetaData::getInstance($connection);
  				}
  				$tableInfo = $this->_meta[$connStr]->getTableInfo($tableName);
  			}
 @@ -123,14 +125,53 @@ class TActiveRecordGateway extends TComponent  		{
  			$builder = $tableInfo->createCommandBuilder($record->getDbConnection());
  			Prado::using('System.Data.DataGateway.TDataGatewayCommand');
 -			$this->_commandBuilders[$connStr] = new TDataGatewayCommand($builder);
 +			$command = new TDataGatewayCommand($builder);
 +			$command->OnCreateCommand[] = array($this, 'onCreateCommand');
 +			$command->OnExecuteCommand[] = array($this, 'onExecuteCommand');
 +			$this->_commandBuilders[$connStr] = $command;
 +
  		}
  		$this->_commandBuilders[$connStr]->getBuilder()->setTableInfo($tableInfo);
 -
 +		$this->_currentRecord=$record;
  		return $this->_commandBuilders[$connStr];
  	}
  	/**
 +	 * Raised when a command is prepared and parameter binding is completed.
 +	 * The parameter object is TDataGatewayEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getCommand Command} property can be
 +	 * inspected to obtain the sql query to be executed.
 +	 * This method also raises the OnCreateCommand event on the ActiveRecord
 +	 * object calling this gateway.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayEventParameter
 +	 */
 +	public function onCreateCommand($sender, $param)
 +	{
 +		$this->raiseEvent('OnCreateCommand', $this, $param);
 +		if($this->_currentRecord!==null)
 +			$this->_currentRecord->onCreateCommand($param);
 +	}
 +
 +	/**
 +	 * Raised when a command is executed and the result from the database was returned.
 +	 * The parameter object is TDataGatewayResultEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getResult Result} property contains
 +	 * the data return from the database. The data returned can be changed
 +	 * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
 +	 * This method also raises the OnCreateCommand event on the ActiveRecord
 +	 * object calling this gateway.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayResultEventParameter
 +	 */
 +	public function onExecuteCommand($sender, $param)
 +	{
 +		$this->raiseEvent('OnExecuteCommand', $this, $param);
 +		if($this->_currentRecord!==null)
 +			$this->_currentRecord->onExecuteCommand($param);
 +	}
 +
 +	/**
  	 * Returns record data matching the given primary key(s). If the table uses
  	 * composite key, specify the name value pairs as an array.
  	 * @param TActiveRecord active record instance.
 @@ -139,7 +180,8 @@ class TActiveRecordGateway extends TComponent  	 */
  	public function findRecordByPK(TActiveRecord $record,$keys)
  	{
 -		return $this->getCommand($record)->findByPk($keys);
 +		$command = $this->getCommand($record);
 +		return $command->findByPk($keys);
  	}
  	/**
 @@ -164,10 +206,8 @@ class TActiveRecordGateway extends TComponent  	 */
  	public function findRecordsByCriteria(TActiveRecord $record, $criteria, $iterator=false)
  	{
 -		if($iterator)
 -			return $this->getCommand($record)->findAll($criteria);
 -		else
 -			return $this->getCommand($record)->find($criteria);
 +		$command = $this->getCommand($record);
 +		return $iterator ? $command->findAll($criteria) : $command->find($criteria);
  	}
  	/**
 @@ -205,6 +245,10 @@ class TActiveRecordGateway extends TComponent  		return $result;
  	}
 +	/**
 +	 * Sets the last insert ID to the corresponding property of the record if available.
 +	 * @param TActiveRecord record for insertion
 +	 */
  	protected function updatePostInsert($record)
  	{
  		$command = $this->getCommand($record);
 @@ -324,91 +368,16 @@ class TActiveRecordGateway extends TComponent  	 * @param string command type
  	 * @param TDbCommand sql command to be executed.
  	 * @param TActiveRecord active record
 -	 * @param mixed data for the command.
 +	 * @param TActiveRecordCriteria data for the command.
  	 */
 -	protected function raiseCommandEvent($type,$command,$record=null,$data=null)
 +	protected function raiseCommandEvent($event,$command,$record,$criteria)
  	{
 -		$param = new TActiveRecordGatewayEventParameter($type,$command,$record,$data);
 +		if(!($criteria instanceof TSqlCriteria))
 +			$criteria = new TActiveRecordCriteria(null,$criteria);
 +		$param = new TActiveRecordEventParameter($command,$record,$criteria);
  		$manager = $record->getRecordManager();
 -		$event = 'on'.$type;
 -		if($data instanceof TActiveRecordCriteria)
 -			$data->{$event}($param);
  		$manager->{$event}($param);
 -	}
 -}
 -
 -/**
 - * Command statement types.
 - *
 - * @author Wei Zhuo <weizho[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Data.ActiveRecord
 - * @since 3.1
 - */
 -class TActiveRecordStatementType
 -{
 -	const Insert='Insert';
 -	const Update='Update';
 -	const Delete='Delete';
 -	const Select='Select';
 -}
 -
 -/**
 - * Active Record command event parameter.
 - *
 - * @author Wei Zhuo <weizho[at]gmail[dot]com>
 - * @version $Id$
 - * @package System.Data.ActiveRecord
 - * @since 3.1
 - */
 -class TActiveRecordGatewayEventParameter extends TActiveRecordEventParameter
 -{
 -	private $_type;
 -	private $_command;
 -	private $_record;
 -	private $_data;
 -
 -	/**
 -	 * New gateway command event parameter.
 -	 */
 -	public function __construct($type,$command,$record=null,$data=null)
 -	{
 -		$this->_type=$type;
 -		$this->_command=$command;
 -		$this->_data=$data;
 -		$this->_record=$record;
 -	}
 -
 -	/**
 -	 * @return string TActiveRecordStateType
 -	 */
 -	public function getType()
 -	{
 -		return $this->_type;
 -	}
 -
 -	/**
 -	 * @return TDbCommand command to be executed.
 -	 */
 -	public function getCommand()
 -	{
 -		return $this->_command;
 -	}
 -
 -	/**
 -	 * @return TActiveRecord active record.
 -	 */
 -	public function getRecord()
 -	{
 -		return $this->_record;
 -	}
 -
 -	/**
 -	 * @return mixed command data.
 -	 */
 -	public function getData()
 -	{
 -		return $this->_data;
 +		$record->{$event}($param);
  	}
  }
 diff --git a/framework/Data/ActiveRecord/TActiveRecordManager.php b/framework/Data/ActiveRecord/TActiveRecordManager.php index 5e463d2d..ab6fe88d 100644 --- a/framework/Data/ActiveRecord/TActiveRecordManager.php +++ b/framework/Data/ActiveRecord/TActiveRecordManager.php @@ -20,20 +20,16 @@ Prado::using('System.Data.ActiveRecord.TActiveRecordStateRegistry');   * TActiveRecordManager provides the default DB connection, default object state
   * registry, default active record gateway, and table meta data inspector.
   *
 - * You can provide a different registry by overriding the {@link createObjectStateRegistry()} method.
 - * Similarly, override {@link createRecordGateway()} for default gateway and override
 - * {@link createMetaDataInspector() }for meta data inspector.
 - *
   * The default connection can be set as follows:
   * <code>
   * TActiveRecordManager::getInstance()->setDbConnection($conn);
   * </code>
   * All new active record created after setting the
 - * {@link DbConnection setDbConnection()} will use that connection.
 + * {@link DbConnection setDbConnection()} will use that connection unless
 + * the custom ActiveRecord class overrides the ActiveRecord::getDbConnection().
   *
 - * The {@link onInsert()}, {@link onUpdate()},
 - * {@link onDelete()} and {@link onSelect()} events are raised
 - * <b>before</b> their respective command are executed.
 + * Set the {@link setCache Cache} property to an ICache object to allow
 + * the active record gateway to cache the table meta data information.
   *
   * @author Wei Zhuo <weizho[at]gmail[dot]com>
   * @version $Id$
 @@ -84,10 +80,12 @@ class TActiveRecordManager extends TComponent  	/**
  	 * @return TActiveRecordManager static instance of record manager.
  	 */
 -	public static function getInstance()
 +	public static function getInstance($self=null)
  	{
  		static $instance;
 -		if($instance===null)
 +		if($self!==null)
 +			$instance=$self;
 +		else if($instance===null)
  			$instance = new self;
  		return $instance;
  	}
 @@ -127,54 +125,6 @@ class TActiveRecordManager extends TComponent  	{
  		return new TActiveRecordGateway($this);
  	}
 -
 -	/**
 -	 * This method is invoked before the object is inserted into the database.
 -	 * The method raises 'OnInsert' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onInsert($param)
 -	{
 -		$this->raiseEvent('OnInsert', $this, $param);
 -	}
 -
 -	/**
 -	 * This method is invoked before the object is deleted from the database.
 -	 * The method raises 'OnDelete' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onDelete($param)
 -	{
 -		$this->raiseEvent('OnDelete', $this, $param);
 -	}
 -
 -	/**
 -	 * This method is invoked before the object data is updated in the database.
 -	 * The method raises 'OnUpdate' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onUpdate($param)
 -	{
 -		$this->raiseEvent('OnUpdate', $this, $param);
 -	}
 -
 -	/**
 -	 * This method is invoked before any select query is executed on the database.
 -	 * The method raises 'OnSelect' event.
 -	 * If you override this method, be sure to call the parent implementation
 -	 * so that the event handlers can be invoked.
 -	 * @param TActiveRecordEventParameter event parameter to be passed to the event handlers
 -	 */
 -	public function onSelect($param)
 -	{
 -		$this->raiseEvent('OnSelect', $this, $param);
 -	}
  }
 diff --git a/framework/Data/Common/Mssql/TMssqlMetaData.php b/framework/Data/Common/Mssql/TMssqlMetaData.php index c70bc349..5d14aac1 100644 --- a/framework/Data/Common/Mssql/TMssqlMetaData.php +++ b/framework/Data/Common/Mssql/TMssqlMetaData.php @@ -1,4 +1,14 @@  <?php
 +/**
 + * TMssqlMetaData class file.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $
 + * @package System.Data.Common.Pgsql
 + */
  /**
   * Load the base TDbMetaData class.
 @@ -6,6 +16,14 @@  Prado::using('System.Data.Common.TDbMetaData');
  Prado::using('System.Data.Common.Mssql.TMssqlTableInfo');
 +/**
 + * TMssqlMetaData loads MSSQL database table and column information.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id: TPgsqlMetaData.php 1866 2007-04-14 05:02:29Z wei $
 + * @package System.Data.Commom.Pgsql
 + * @since 3.1
 + */
  class TMssqlMetaData extends TDbMetaData
  {
  	/**
 @@ -45,9 +63,15 @@ EOD;  				$tableInfo = $this->createNewTableInfo($col);
  			$this->processColumn($tableInfo,$col);
  		}
 +		if($tableInfo===null)
 +			throw new TDbException('dbmetadata_invalid_table_view', $table);
  		return $tableInfo;
  	}
 +	/**
 +	 * @param string table name
 +	 * @return array tuple($catalogName,$schemaName,$tableName)
 +	 */
  	protected function getCatalogSchemaTableName($table)
  	{
  		//remove possible delimiters
 diff --git a/framework/Data/Common/Mssql/TMssqlTableColumn.php b/framework/Data/Common/Mssql/TMssqlTableColumn.php index 77c115e5..f108248d 100644 --- a/framework/Data/Common/Mssql/TMssqlTableColumn.php +++ b/framework/Data/Common/Mssql/TMssqlTableColumn.php @@ -37,16 +37,25 @@ class TMssqlTableColumn extends TDbTableColumn  		return 'string';
  	}
 +	/**
 +	 * @return boolean true if the column has identity (auto-increment)
 +	 */
  	public function getAutoIncrement()
  	{
  		return $this->getInfo('AutoIncrement',false);
  	}
 +	/**
 +	 * @return boolean true if auto increments.
 +	 */
  	public function hasSequence()
  	{
  		return $this->getAutoIncrement();
  	}
 +	/**
 +	 * @return boolean true if db type is 'timestamp'.
 +	 */
  	public function getIsExcluded()
  	{
  		return strtolower($this->getDbType())==='timestamp';
 diff --git a/framework/Data/Common/Mssql/TMssqlTableInfo.php b/framework/Data/Common/Mssql/TMssqlTableInfo.php index b407ad44..e408440b 100644 --- a/framework/Data/Common/Mssql/TMssqlTableInfo.php +++ b/framework/Data/Common/Mssql/TMssqlTableInfo.php @@ -34,6 +34,9 @@ class TMssqlTableInfo extends TDbTableInfo  		return $this->getInfo('SchemaName');
  	}
 +	/**
 +	 * @return string catalog name (database name)
 +	 */
  	public function getCatalogName()
  	{
  		return $this->getInfo('CatalogName');
 @@ -44,6 +47,7 @@ class TMssqlTableInfo extends TDbTableInfo  	 */
  	public function getTableFullName()
  	{
 +		//MSSQL alway returns the catalog, schem and table names.
  		return '['.$this->getCatalogName().'].['.$this->getSchemaName().'].['.$this->getTableName().']';
  	}
 diff --git a/framework/Data/Common/Mysql/TMysqlMetaData.php b/framework/Data/Common/Mysql/TMysqlMetaData.php index 9e947298..32d5114f 100644 --- a/framework/Data/Common/Mysql/TMysqlMetaData.php +++ b/framework/Data/Common/Mysql/TMysqlMetaData.php @@ -26,6 +26,8 @@ class TMysqlMetaData extends TDbMetaData  			$col['index'] = $index++;
  			$this->processColumn($tableInfo,$col);
  		}
 +		if($index===0)
 +			throw new TDbException('dbmetadata_invalid_table_view', $table);
  		return $tableInfo;
  	}
 diff --git a/framework/Data/Common/Pgsql/TPgsqlMetaData.php b/framework/Data/Common/Pgsql/TPgsqlMetaData.php index ac7e6b7a..bb03b6cd 100644 --- a/framework/Data/Common/Pgsql/TPgsqlMetaData.php +++ b/framework/Data/Common/Pgsql/TPgsqlMetaData.php @@ -109,6 +109,8 @@ EOD;  			$col['index'] = $index++;
  			$this->processColumn($tableInfo, $col);
  		}
 +		if($index===0)
 +			throw new TDbException('dbmetadata_invalid_table_view', $table);
  		return $tableInfo;
  	}
 diff --git a/framework/Data/Common/Sqlite/TSqliteMetaData.php b/framework/Data/Common/Sqlite/TSqliteMetaData.php index 2ce46fb7..6fcf7b7f 100644 --- a/framework/Data/Common/Sqlite/TSqliteMetaData.php +++ b/framework/Data/Common/Sqlite/TSqliteMetaData.php @@ -52,6 +52,8 @@ class TSqliteMetaData extends TDbMetaData  		$info['TableName'] = $table;
  		if($this->getIsView($tableName))
  			$info['IsView'] = true;
 +		if(count($columns)===0)
 +			throw new TDbException('dbmetadata_invalid_table_view', $tableName);
  		$tableInfo = new TSqliteTableInfo($info,$primary,$foreign);
  		$tableInfo->getColumns()->copyFrom($columns);
  		return $tableInfo;
 diff --git a/framework/Data/Common/Sqlite/TSqliteTableColumn.php b/framework/Data/Common/Sqlite/TSqliteTableColumn.php index b8287218..80dcd9d9 100644 --- a/framework/Data/Common/Sqlite/TSqliteTableColumn.php +++ b/framework/Data/Common/Sqlite/TSqliteTableColumn.php @@ -25,6 +25,9 @@ Prado::using('System.Data.Common.TDbTableColumn');   */
  class TSqliteTableColumn extends TDbTableColumn
  {
 +	/**
 +	 * @TODO add sqlite types.
 +	 */
  	private static $types = array();
  	/**
 diff --git a/framework/Data/Common/TDbMetaData.php b/framework/Data/Common/TDbMetaData.php index 6838d7dc..d0963f44 100644 --- a/framework/Data/Common/TDbMetaData.php +++ b/framework/Data/Common/TDbMetaData.php @@ -47,7 +47,7 @@ abstract class TDbMetaData extends TComponent  	 * @param TDbConnection database connection.
  	 * @return TDbMetaData database specific TDbMetaData.
  	 */
 -	public static function getMetaData($conn)
 +	public static function getInstance($conn)
  	{
  		$conn->setActive(true); //must be connected before retrieving driver name
  		$driver = $conn->getDriverName();
 diff --git a/framework/Data/Common/TDbTableColumn.php b/framework/Data/Common/TDbTableColumn.php index 6ff2ff46..84fb238c 100644 --- a/framework/Data/Common/TDbTableColumn.php +++ b/framework/Data/Common/TDbTableColumn.php @@ -100,7 +100,7 @@ class TDbTableColumn extends TComponent  	}
  	/**
 -	 * @return integer one-based ordinal position of the column in the table.
 +	 * @return integer zero-based ordinal position of the column in the table.
  	 */
  	public function getColumnIndex()
  	{
 diff --git a/framework/Data/DataGateway/TDataGatewayCommand.php b/framework/Data/DataGateway/TDataGatewayCommand.php index 8a340ee7..dbabd2b7 100644 --- a/framework/Data/DataGateway/TDataGatewayCommand.php +++ b/framework/Data/DataGateway/TDataGatewayCommand.php @@ -1,5 +1,39 @@  <?php +/**
 + * TDataGatewayCommand, TDataGatewayEventParameter and TDataGatewayResultEventParameter class file.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.DataGateway
 + */
 +/**
 + * TDataGatewayCommand is command builder and executor class for
 + * TTableGateway and TActiveRecordGateway.
 + *
 + * TDataGatewayCommand builds the TDbCommand for TTableGateway
 + * and TActiveRecordGateway commands such as find(), update(), insert(), etc,
 + * using the TDbCommandBuilder classes (database specific TDbCommandBuilder
 + * classes are used).
 + *
 + * Once the command is built and the query parameters are binded, the
 + * {@link OnCreateCommand} event is raised. Event handlers for the OnCreateCommand
 + * event should not alter the Command property nor the Criteria property of the
 + * TDataGatewayEventParameter.
 + *
 + * TDataGatewayCommand excutes the TDbCommands and returns the result obtained from the
 + * database (returned value depends on the method executed). The
 + * {@link OnExecuteCommand} event is raised after the command is executed and resulting
 + * data is set in the TDataGatewayResultEventParameter object's Result property.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.DataGateway
 + * @since 3.1
 + */
  class TDataGatewayCommand extends TComponent
  {
  	private $_builder;
 @@ -46,6 +80,7 @@ class TDataGatewayCommand extends TComponent  		$where = $criteria->getCondition();
  		$parameters = $criteria->getParameters()->toArray();
  		$command = $this->getBuilder()->createDeleteCommand($where, $parameters);
 +		$this->onCreateCommand($command,$criteria);
  		$command->prepare();
  		return $command->execute();
  	}
 @@ -61,8 +96,9 @@ class TDataGatewayCommand extends TComponent  		$where = $criteria->getCondition();
  		$parameters = $criteria->getParameters()->toArray();
  		$command = $this->getBuilder()->createUpdateCommand($data,$where, $parameters);
 +		$this->onCreateCommand($command,$criteria);
  		$command->prepare();
 -		return $command->execute();
 +		return $this->onExecuteCommand($command, $command->execute());
  	}
  	/**
 @@ -83,7 +119,8 @@ class TDataGatewayCommand extends TComponent  	 */
  	public function find($criteria)
  	{
 -		return $this->getFindCommand($criteria)->queryRow();
 +		$command = $this->getFindCommand($criteria);
 +		return $this->onExecuteCommand($command, $command->queryRow());
  	}
  	/**
 @@ -93,7 +130,27 @@ class TDataGatewayCommand extends TComponent  	 */
  	public function findAll($criteria)
  	{
 -		return $this->getFindCommand($criteria)->query();
 +		$command = $this->getFindCommand($criteria);
 +		return $this->onExecuteCommand($command, $command->query());
 +	}
 +
 +	/**
 +	 * Build the find command from the criteria. Limit, Offset and Ordering are applied if applicable.
 +	 * @param TSqlCriteria $criteria
 +	 * @return TDbCommand.
 +	 */
 +	protected function getFindCommand($criteria)
 +	{
 +		if($criteria===null)
 +			return $this->getBuilder()->createFindCommand();
 +		$where = $criteria->getCondition();
 +		$parameters = $criteria->getParameters()->toArray();
 +		$ordering = $criteria->getOrdersBy();
 +		$limit = $criteria->getLimit();
 +		$offset = $criteria->getOffset();
 +		$command = $this->getBuilder()->createFindCommand($where,$parameters,$ordering,$limit,$offset);
 +		$this->onCreateCommand($command, $criteria);
 +		return $command;
  	}
  	/**
 @@ -104,7 +161,8 @@ class TDataGatewayCommand extends TComponent  	{
  		list($where, $parameters) = $this->getPrimaryKeyCondition((array)$keys);
  		$command = $this->getBuilder()->createFindCommand($where, $parameters);
 -		return $command->queryRow();
 +		$this->onCreateCommand($command, new TSqlCriteria($where,$parameters));
 +		return $this->onExecuteCommand($command, $command->queryRow());
  	}
  	/**
 @@ -115,7 +173,8 @@ class TDataGatewayCommand extends TComponent  	{
  		$where = $this->getCompositeKeyCondition((array)$keys);
  		$command = $this->getBuilder()->createFindCommand($where);
 -		return $command->query();
 +		$this->onCreateCommand($command, new TSqlCriteria($where,$keys));
 +		return $this->onExecuteCommand($command,$command->query());
  	}
  	/**
 @@ -126,8 +185,9 @@ class TDataGatewayCommand extends TComponent  	{
  		$where = $this->getCompositeKeyCondition((array)$keys);
  		$command = $this->getBuilder()->createDeleteCommand($where);
 +		$this->onCreateCommand($command, new TSqlCriteria($where,$keys));
  		$command->prepare();
 -		return $command->execute();
 +		return $this->onExecuteCommand($command,$command->execute());
  	}
  	/**
 @@ -209,7 +269,8 @@ class TDataGatewayCommand extends TComponent  	 */
  	public function findBySql($criteria)
  	{
 -		return $this->getSqlCommand($criteria)->query();
 +		$command = $this->getSqlCommand($criteria);
 +		return $this->onExecuteCommand($command, $command->query());
  	}
  	/**
 @@ -229,27 +290,11 @@ class TDataGatewayCommand extends TComponent  			$sql = $this->getBuilder()->applyLimitOffset($sql, $limit, $offset);
  		$command = $this->getBuilder()->createCommand($sql);
  		$this->getBuilder()->bindArrayValues($command, $criteria->getParameters()->toArray());
 +		$this->onCreateCommand($command, $criteria);
  		return $command;
  	}
  	/**
 -	 * Build the find command from the criteria. Limit, Offset and Ordering are applied if applicable.
 -	 * @param TSqlCriteria $criteria
 -	 * @return TDbCommand.
 -	 */
 -	protected function getFindCommand($criteria)
 -	{
 -		if($criteria===null)
 -			return $this->getBuilder()->createFindCommand();
 -		$where = $criteria->getCondition();
 -		$parameters = $criteria->getParameters()->toArray();
 -		$ordering = $criteria->getOrdersBy();
 -		$limit = $criteria->getLimit();
 -		$offset = $criteria->getOffset();
 -		return $this->getBuilder()->createFindCommand($where,$parameters,$ordering,$limit,$offset);
 -	}
 -
 -	/**
  	 * @param TSqlCriteria $criteria
  	 * @return integer number of records.
  	 */
 @@ -263,7 +308,8 @@ class TDataGatewayCommand extends TComponent  		$limit = $criteria->getLimit();
  		$offset = $criteria->getOffset();
  		$command = $this->getBuilder()->createCountCommand($where,$parameters,$ordering,$limit,$offset);
 -		return intval($command->queryScalar());
 +		$this->onCreateCommand($command, $criteria);
 +		return $this->onExecuteCommand($command, intval($command->queryScalar()));
  	}
  	/**
 @@ -276,8 +322,9 @@ class TDataGatewayCommand extends TComponent  	public function insert($data)
  	{
  		$command=$this->getBuilder()->createInsertCommand($data);
 +		$this->onCreateCommand($command, new TSqlCriteria(null,$data));
  		$command->prepare();
 -		if($command->execute() > 0)
 +		if($this->onExecuteCommand($command, $command->execute()) > 0)
  		{
  			$value = $this->getLastInsertId();
  			return $value !== null ? $value : true;
 @@ -344,6 +391,120 @@ class TDataGatewayCommand extends TComponent  		}
  		return $fields;
  	}
 +
 +	/**
 +	 * Raised when a command is prepared and parameter binding is completed.
 +	 * The parameter object is TDataGatewayEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getCommand Command} property can be
 +	 * inspected to obtain the sql query to be executed.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayEventParameter
 +	 */
 +	public function onCreateCommand($command, $criteria)
 +	{
 +		$this->raiseEvent('OnCreateCommand', $this, new TDataGatewayEventParameter($command,$criteria));
 +	}
 +
 +	/**
 +	 * Raised when a command is executed and the result from the database was returned.
 +	 * The parameter object is TDataGatewayResultEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getResult Result} property contains
 +	 * the data return from the database. The data returned can be changed
 +	 * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayResultEventParameter
 +	 */
 +	public function onExecuteCommand($command, $result)
 +	{
 +		$parameter = new TDataGatewayResultEventParameter($command, $result);
 +		$this->raiseEvent('OnExecuteCommand', $this, $parameter);
 +		return $parameter->getResult();
 +	}
 +}
 +
 +/**
 + * TDataGatewayEventParameter class contains the TDbCommand to be executed as
 + * well as the criteria object.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.DataGateway
 + * @since 3.1
 + */
 +class TDataGatewayEventParameter extends TEventParameter
 +{
 +	private $_command;
 +	private $_criteria;
 +
 +	public function __construct($command,$criteria)
 +	{
 +		$this->_command=$command;
 +		$this->_criteria=$criteria;
 +	}
 +
 +	/**
 +	 * The database command to be executed. Do not rebind the parameters or change
 +	 * the sql query string.
 +	 * @return TDbCommand command to be executed.
 +	 */
 +	public function getCommand()
 +	{
 +		return $this->_command;
 +	}
 +
 +	/**
 +	 * @return TSqlCriteria criteria used to bind the sql query parameters.
 +	 */
 +	public function getCriteria()
 +	{
 +		return $this->_criteria;
 +	}
 +}
 +
 +/**
 + * TDataGatewayResultEventParameter contains the TDbCommand executed and the resulting
 + * data returned from the database. The data can be changed by changing the
 + * {@link setResult Result} property.
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.DataGateway
 + * @since 3.1
 + */
 +class TDataGatewayResultEventParameter extends TEventParameter
 +{
 +	private $_command;
 +	private $_result;
 +
 +	public function __construct($command,$result)
 +	{
 +		$this->_command=$command;
 +		$this->_result=$result;
 +	}
 +
 +	/**
 +	 * @return TDbCommand database command executed.
 +	 */
 +	public function getCommand()
 +	{
 +		return $this->_command;
 +	}
 +
 +	/**
 +	 * @return mixed result returned from executing the command.
 +	 */
 +	public function getResult()
 +	{
 +		return $this->_result;
 +	}
 +
 +	/**
 +	 * @param mixed change the result returned by the gateway.
 +	 */
 +	public function setResult($value)
 +	{
 +		$this->_result=$value;
 +	}
  }
  ?>
\ No newline at end of file diff --git a/framework/Data/DataGateway/TSqlCriteria.php b/framework/Data/DataGateway/TSqlCriteria.php index ac5f00f2..d073cd10 100644 --- a/framework/Data/DataGateway/TSqlCriteria.php +++ b/framework/Data/DataGateway/TSqlCriteria.php @@ -7,7 +7,7 @@   * @copyright Copyright © 2005-2007 PradoSoft
   * @license http://www.pradosoft.com/license/
   * @version $Id: TDbSqlCriteria.php 1835 2007-04-03 01:38:15Z wei $
 - * @package System.Data.Common
 + * @package System.Data.DataGateway
   */
  /**
 @@ -26,7 +26,7 @@   *
   * @author Wei Zhuo <weizho[at]gmail[dot]com>
   * @version $Id: TDbSqlCriteria.php 1835 2007-04-03 01:38:15Z wei $
 - * @package System.Data.Common
 + * @package System.Data.DataGateway
   * @since 3.1
   */
  class TSqlCriteria extends TComponent
 diff --git a/framework/Data/DataGateway/TTableGateway.php b/framework/Data/DataGateway/TTableGateway.php index 6a77c064..f278eed5 100644 --- a/framework/Data/DataGateway/TTableGateway.php +++ b/framework/Data/DataGateway/TTableGateway.php @@ -1,27 +1,163 @@ -<?php +<?php
 +/**
 + * TTableGateway class file.
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005-2007 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id$
 + * @package System.Data.DataGateway
 + */
 +/**
 + * Loads the data gateway command builder and sql criteria.
 + */
  Prado::using('System.Data.DataGateway.TSqlCriteria');
  Prado::using('System.Data.DataGateway.TDataGatewayCommand');
 +/**
 + * TTableGateway class provides several find methods to get data from the database
 + * and update, insert, and delete methods.
 + *
 + * Each method maps the input parameters into a SQL call and executes the SQL
 + * against a database connection. The TTableGateway is stateless
 + * (with respect to the data and data objects), as its role is to push data back and forth.
 + *
 + * Example usage:
 + * <code>
 + * //create a connection
 + * $dsn = 'pgsql:host=localhost;dbname=test';
 + * $conn = new TDbConnection($dsn, 'dbuser','dbpass');
 + *
 + * //create a table gateway for table/view named 'address'
 + * $table = new TTableGateway('address', $conn);
 + *
 + * //insert a new row, returns last insert id (if applicable)
 + * $id = $table->insert(array('name'=>'wei', 'phone'=>'111111'));
 + *
 + * $record1 = $table->findByPk($id); //find inserted record
 + *
 + * //finds all records, returns an iterator
 + * $records = $table->findAll();
 + * print_r($records->readAll());
 + *
 + * //update the row
 + * $table->updateByPk($record1, $id);
 + * </code>
 + *
 + * All methods that may return more than one row of data will return an
 + * TDbDataReader iterator.
 + *
 + * The OnCreateCommand event is raised when a command is prepared and parameter
 + * binding is completed. The parameter object is a TDataGatewayEventParameter of which the
 + * {@link TDataGatewayEventParameter::getCommand Command} property can be
 + * inspected to obtain the sql query to be executed.
 + *
 + * The OnExecuteCommand	event is raised when a command is executed and the result
 + * from the database was returned. The parameter object is a
 + * TDataGatewayResultEventParameter of which the
 + * {@link TDataGatewayEventParameter::getResult Result} property contains
 + * the data return from the database. The data returned can be changed
 + * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
 + *
 + * <code>
 + * $table->OnCreateCommand[] = 'log_it'; //any valid PHP callback statement
 + * $table->OnExecuteCommand[] = array($obj, 'method_name'); // calls 'method_name' on $obj
 + *
 + * function log_it($sender, $param)
 + * {
 + *     var_dump($param); //TDataGatewayEventParameter object.
 + * }
 + * </code>
 + *
 + * @author Wei Zhuo <weizho[at]gmail[dot]com>
 + * @version $Id$
 + * @package System.Data.DataGateway
 + * @since 3.1
 + */
  class TTableGateway extends TComponent
  {
  	private $_command;
  	private $_connection;
 -	public function __construct($tableName,$connection)
 +	/**
 +	 * Creates a new generic table gateway for a given table or view name
 +	 * and a database connection.
 +	 * @param string|TDbTableInfo table or view name or table information.
 +	 * @param TDbConnection database connection.
 +	 */
 +	public function __construct($table,$connection)
  	{
  		$this->_connection=$connection;
 -		$this->setTableName($tableName);
 +		if(is_string($table))
 +			$this->setTableName($table);
 +		else if($table instanceof TDbTableInfo)
 +			$this->setTableInfo($table);
 +		else
 +			throw new TDbException('dbtablegateway_invalid_table_info');
 +	}
 +
 +	/**
 +	 * @param TDbTableInfo table or view information.
 +	 */
 +	protected function setTableInfo($tableInfo)
 +	{
 +		$builder = $tableInfo->createCommandBuilder($this->getDbConnection());
 +		$this->initCommandBuilder($builder);
  	}
 +	/**
 +	 * Sets up the command builder for the given table.
 +	 * @param string table or view name.
 +	 */
  	protected function setTableName($tableName)
  	{
  		Prado::using('System.Data.Common.TDbMetaData');
 -		$meta = TDbMetaData::getMetaData($this->getDbConnection());
 -		$builder = $meta->createCommandBuilder($tableName);
 +		$meta = TDbMetaData::getInstance($this->getDbConnection());
 +		$this->initCommandBuilder($meta->createCommandBuilder($tableName));
 +	}
 +
 +	/**
 +	 * @param TDbCommandBuilder database specific command builder.
 +	 */
 +	protected function initCommandBuilder($builder)
 +	{
  		$this->_command = new TDataGatewayCommand($builder);
 +		$this->_command->OnCreateCommand[] = array($this, 'onCreateCommand');
 +		$this->_command->OnExecuteCommand[] = array($this, 'onExecuteCommand');
  	}
 +	/**
 +	 * Raised when a command is prepared and parameter binding is completed.
 +	 * The parameter object is TDataGatewayEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getCommand Command} property can be
 +	 * inspected to obtain the sql query to be executed.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayEventParameter
 +	 */
 +	public function onCreateCommand($sender, $param)
 +	{
 +		$this->raiseEvent('OnCreateCommand', $this, $param);
 +	}
 +
 +	/**
 +	 * Raised when a command is executed and the result from the database was returned.
 +	 * The parameter object is TDataGatewayResultEventParameter of which the
 +	 * {@link TDataGatewayEventParameter::getResult Result} property contains
 +	 * the data return from the database. The data returned can be changed
 +	 * by setting the {@link TDataGatewayEventParameter::setResult Result} property.
 +	 * @param TDataGatewayCommand originator $sender
 +	 * @param TDataGatewayResultEventParameter
 +	 */
 +	public function onExecuteCommand($sender, $param)
 +	{
 +		$this->raiseEvent('OnExecuteCommand', $this, $param);
 +	}
 +
 +	/**
 +	 * @return TDataGatewayCommand command builder and executor.
 +	 */
  	protected function getCommand()
  	{
  		return $this->_command;
 diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index ca7faed1..b3074ad6 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -371,12 +371,15 @@ dbcommandbuilder_value_must_not_be_null	= Property {0} must not be null as defin  dbcommon_invalid_table_name				= Database table '{0}' not found. Error Msg: {1}.
  dbcommon_invalid_identifier_name        = Invalid database identifier name '{0}', see {1} for details.
  dbtableinfo_invalid_column_name			= Invalid column name '{0}' for database table '{1}'.
 +dbmetadata_invalid_table_view			= Invalid table/view name '{0}', or that table/view '{0}' contains no accessible column/field definitions.
 +
  dbtablegateway_invalid_criteria			= Invalid criteria object, must be a string or instance of TSqlCriteria.
  dbtablegateway_no_primary_key_found		= Table '{0}' does not contain any primary key fields.
  dbtablegateway_missing_pk_values		= Missing primary key values in forming IN(key1, key2, ...) for table '{0}'.
  dbtablegateway_pk_value_count_mismatch	= Composite key value count mismatch in forming IN( (key1, key2, ..), (key3, key4, ..)) for table '{0}'.
  dbtablegateway_mismatch_args_exception	= TTableGateway finder method '{0}' expects {1} parameters but found only {2} parameters instead.
  dbtablegateway_mismatch_column_name		= In dynamic __call() method '{0}', no matching columns were found, valid columns for table '{2}' are '{1}'.
 +dbtablegateway_invalid_table_info		= Table must be a string or an instanceof TDbTableInfo.
  directorycachedependency_directory_invalid = TDirectoryCacheDependency.Directory {0} does not refer to a valid directory.
  cachedependencylist_cachedependency_required = Only objects implementing ICacheDependency can be added into TCacheDependencyList.
 diff --git a/tests/simple_unit/ActiveRecord/RecordEventTestCase.php b/tests/simple_unit/ActiveRecord/RecordEventTestCase.php index c669bb72..fad54eb0 100644 --- a/tests/simple_unit/ActiveRecord/RecordEventTestCase.php +++ b/tests/simple_unit/ActiveRecord/RecordEventTestCase.php @@ -9,24 +9,28 @@ class RecordEventTestCase extends UnitTestCase  		$conn = new TDbConnection('pgsql:host=localhost;dbname=test', 'test','test');
  		TActiveRecordManager::getInstance()->setDbConnection($conn);
  	}
 -
 +/*
  	function testFindByPk()
  	{
  		$user1 = UserRecord::finder()->findByPk('admin');
  		$this->assertNotNull($user1);
  	}
 -
 +*/
  	function test_same_data_returns_same_object()
  	{
  		$criteria = new TActiveRecordCriteria('username = ?', 'admin');
 -		$criteria->OnSelect = array($this, 'logger');
 -		$user1 = UserRecord::finder()->find($criteria);
 -		//var_dump($user1);
 +		$finder = new UserRecord();
 +		$finder->OnCreateCommand[] = array($this, 'logger');
 +		$finder->OnExecuteCommand[] = array($this, 'logger');
 +		$user1 = $finder->find($criteria);
 +		var_dump($user1);
 +
 +		var_dump(UserRecord::finder()->find($criteria));
  	}
  	function logger($sender, $param)
  	{
 -		var_dump($param->Command->Text);
 +		var_dump($param);
  	}
  }
 diff --git a/tests/simple_unit/SqlMap/ActiveRecordSqlMapTest.php b/tests/simple_unit/SqlMap/ActiveRecordSqlMapTest.php index 63d62534..81ce93bb 100644 --- a/tests/simple_unit/SqlMap/ActiveRecordSqlMapTest.php +++ b/tests/simple_unit/SqlMap/ActiveRecordSqlMapTest.php @@ -65,7 +65,9 @@ class ActiveRecordSqlMapTest extends BaseCase  		$this->assertTrue($record->save());
  		$check1 = $this->sqlmap->queryForObject('GetActiveRecordAccounts');
 -		$check2 = ActiveAccount::finder()->findByAccount_FirstName($record->Account_FirstName);
 +		$finder = ActiveAccount::finder();
 +		$check2 = $finder->findByAccount_FirstName($record->Account_FirstName);
 +
  		$this->assertSameAccount($record,$check1);
  		$this->assertSameAccount($record,$check2);
 diff --git a/tests/simple_unit/TableGateway/BaseGatewayTest.php b/tests/simple_unit/TableGateway/BaseGatewayTest.php index 825f2d0e..ff7a58b0 100644 --- a/tests/simple_unit/TableGateway/BaseGatewayTest.php +++ b/tests/simple_unit/TableGateway/BaseGatewayTest.php @@ -88,7 +88,7 @@ class BaseGatewayTest extends UnitTestCase  	}
  	function delete_all()
  	{
 -		$this->getGateway()->deleteAll('true');
 +		$this->getGateway()->deleteAll('1=1');
  	}
  }  ?>
\ No newline at end of file diff --git a/tests/simple_unit/TableGateway/TableInfoGatewayTest.php b/tests/simple_unit/TableGateway/TableInfoGatewayTest.php new file mode 100644 index 00000000..2be848c5 --- /dev/null +++ b/tests/simple_unit/TableGateway/TableInfoGatewayTest.php @@ -0,0 +1,17 @@ +<?php +
 +require_once(dirname(__FILE__).'/BaseGatewayTest.php');
 +
 +class TableInfoGatewayTest extends BaseGatewayTest
 +{
 +	function test_table_info()
 +	{
 +		$conn = $this->getGateway()->getDbConnection();
 +		$this->add_record1();
 +		$this->add_record2();
 +		$info = TDbMetaData::getInstance($conn)->getTableInfo('address');
 +		$table = new TTableGateway($info, $conn);
 +		$this->assertEqual(count($table->findAll()->readAll()), 2);
 +	}
 +} +?>
\ No newline at end of file | 
