summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwei <>2007-05-03 00:48:04 +0000
committerwei <>2007-05-03 00:48:04 +0000
commit1ae09931b2572d9c3067c99f841a60cb3330b3f3 (patch)
tree0b263b594bfa9c2bf5b37d2d565b4583f796bf2c
parent24bdc94145c11744f624149a0dbdd10e3d5ca4cd (diff)
Update active relations docs
-rw-r--r--.gitattributes6
-rw-r--r--demos/quickstart/protected/pages/Database/ActiveRecord.page29
-rw-r--r--demos/quickstart/protected/pages/Database/ar_objects.pngbin0 -> 14323 bytes
-rw-r--r--demos/quickstart/protected/pages/Database/ar_objects.vsdbin0 -> 183296 bytes
-rw-r--r--demos/quickstart/protected/pages/Database/ar_relations.pngbin0 -> 9278 bytes
-rw-r--r--demos/quickstart/protected/pages/Database/ar_relations.vsdbin0 -> 97280 bytes
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php20
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php8
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php107
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php14
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php11
-rw-r--r--framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php13
-rw-r--r--framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php1
-rw-r--r--framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php18
-rw-r--r--framework/Data/ActiveRecord/Scaffold/TScaffoldView.php4
-rw-r--r--framework/Data/ActiveRecord/TActiveRecord.php1
-rw-r--r--framework/Data/Common/Mssql/TMssqlCommandBuilder.php6
-rw-r--r--framework/Data/Common/Mssql/TMssqlTableInfo.php1
-rw-r--r--framework/Data/Common/Sqlite/TSqliteCommandBuilder.php48
-rw-r--r--framework/Data/Common/Sqlite/TSqliteMetaData.php2
-rw-r--r--framework/Data/Common/Sqlite/TSqliteTableInfo.php9
-rw-r--r--framework/Data/Common/TDbCommandBuilder.php39
-rwxr-xr-xframework/prado-cli.php5
-rw-r--r--tests/FunctionalTests/tickets/protected/pages/Ticket614.page13
24 files changed, 277 insertions, 78 deletions
diff --git a/.gitattributes b/.gitattributes
index eee67148..ca665df6 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1268,6 +1268,10 @@ demos/quickstart/protected/pages/Database/Samples/Scaffold/sqlite.db -text
demos/quickstart/protected/pages/Database/Samples/config.xml -text
demos/quickstart/protected/pages/Database/Scaffold.page -text
demos/quickstart/protected/pages/Database/SqlMap.page -text
+demos/quickstart/protected/pages/Database/ar_objects.png -text
+demos/quickstart/protected/pages/Database/ar_objects.vsd -text
+demos/quickstart/protected/pages/Database/ar_relations.png -text
+demos/quickstart/protected/pages/Database/ar_relations.vsd -text
demos/quickstart/protected/pages/Database/diagram.png -text
demos/quickstart/protected/pages/Database/object_states.png -text
demos/quickstart/protected/pages/Database/sqlmap_active_record.png -text
@@ -1646,6 +1650,7 @@ framework/Data/Common/Mysql/TMysqlTableInfo.php -text
framework/Data/Common/Pgsql/TPgsqlMetaData.php -text
framework/Data/Common/Pgsql/TPgsqlTableColumn.php -text
framework/Data/Common/Pgsql/TPgsqlTableInfo.php -text
+framework/Data/Common/Sqlite/TSqliteCommandBuilder.php -text
framework/Data/Common/Sqlite/TSqliteMetaData.php -text
framework/Data/Common/Sqlite/TSqliteTableColumn.php -text
framework/Data/Common/Sqlite/TSqliteTableInfo.php -text
@@ -2540,6 +2545,7 @@ tests/FunctionalTests/tickets/protected/pages/Ticket587.page -text
tests/FunctionalTests/tickets/protected/pages/Ticket587.php -text
tests/FunctionalTests/tickets/protected/pages/Ticket605.page -text
tests/FunctionalTests/tickets/protected/pages/Ticket606.page -text
+tests/FunctionalTests/tickets/protected/pages/Ticket614.page -text
tests/FunctionalTests/tickets/protected/pages/Ticket68.page -text
tests/FunctionalTests/tickets/protected/pages/Ticket72.page -text
tests/FunctionalTests/tickets/protected/pages/Ticket72.php -text
diff --git a/demos/quickstart/protected/pages/Database/ActiveRecord.page b/demos/quickstart/protected/pages/Database/ActiveRecord.page
index c3cf663b..967aae89 100644
--- a/demos/quickstart/protected/pages/Database/ActiveRecord.page
+++ b/demos/quickstart/protected/pages/Database/ActiveRecord.page
@@ -49,15 +49,20 @@
<li>Finder methods to wrap commonly used SQL queries and return Active Record objects.</li>
<li>Update existing records and insert new records into the database.</li>
</ul>
+<h2>Database Supported</h2>
<p id="p1" class="block-content">
The Active Record implementation utilizes the <a href="?page=Database.DAO">Prado DAO</a> classes for data access.
-The current Active Record implementation supports
-<a href="http://www.mysql.com">MySQL</a>,
-<a href="http://www.postgres.com">Postgres SQL</a> and
-<a href="http://www.sqlite.org">SQLite</a> databases.
-Support for other databases can be provided when there are sufficient demand.
+The current Active Record implementation supports the following database.
</p>
-<h2 id="138048">Defining an Active Record</h2>
+<ul>
+ <li><a href="http://www.mysql.com">MySQL 4.1 or later</a></li>
+ <li><a href="http://www.postgres.com">Postgres SQL 7.3 or later</a></li>
+ <li><a href="http://www.sqlite.org">SQLite 2 and 3</a></li>
+ <li><a href="#">MS SQL 2000 or later</a></li>
+</ul>
+<p>Support for other databases can be provided when there are sufficient demand.</p>
+
+<h1 id="138048">Defining an Active Record</h1>
<p id="690483" class="block-content">Let us
consider the following "users" table that contains two columns named "username" and "email",
where "username" is also the primary key.
@@ -412,6 +417,18 @@ catch(Exception $e) // an exception is raised if a query fails
}
</com:TTextHighlighter>
+<h1 id="ar_relations">Active Record Relationships</h1>
+<p id="690504a" class="block-content">
+The Prado ActiveRecord implementation supports the foreign key mappings for database
+that supports foreign key contraints. For ActiveRecord relationships to function the
+underlying database must support foreign key constraints (e.g. MySQL with InnoDB).
+</p>
+
+<h2>Foreign Key Mapping</h2>
+
+
+<h2>Association Table Mapping</h2>
+
<h2 id="138054">References</h2>
<ul id="u3" class="block-content">
<li>Fowler et. al. <i>Patterns of Enterprise Application Architecture</i>,
diff --git a/demos/quickstart/protected/pages/Database/ar_objects.png b/demos/quickstart/protected/pages/Database/ar_objects.png
new file mode 100644
index 00000000..027d1e96
--- /dev/null
+++ b/demos/quickstart/protected/pages/Database/ar_objects.png
Binary files differ
diff --git a/demos/quickstart/protected/pages/Database/ar_objects.vsd b/demos/quickstart/protected/pages/Database/ar_objects.vsd
new file mode 100644
index 00000000..595b7d86
--- /dev/null
+++ b/demos/quickstart/protected/pages/Database/ar_objects.vsd
Binary files differ
diff --git a/demos/quickstart/protected/pages/Database/ar_relations.png b/demos/quickstart/protected/pages/Database/ar_relations.png
new file mode 100644
index 00000000..df72823c
--- /dev/null
+++ b/demos/quickstart/protected/pages/Database/ar_relations.png
Binary files differ
diff --git a/demos/quickstart/protected/pages/Database/ar_relations.vsd b/demos/quickstart/protected/pages/Database/ar_relations.vsd
new file mode 100644
index 00000000..9b27e7e3
--- /dev/null
+++ b/demos/quickstart/protected/pages/Database/ar_relations.vsd
Binary files differ
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php
index c72ba160..1168bf55 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordBelongsTo.php
@@ -1,6 +1,6 @@
<?php
/**
- * TActiveRecordBelongsTo class file.
+ * TActiveRecordBelongsTo class file.
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @link http://www.pradosoft.com/
@@ -16,8 +16,8 @@
Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
/**
- * Implements the foreign key relationship (TActiveRecord::BELONGS_TO) between
- * the source objects and the related foreign object. Consider the
+ * Implements the foreign key relationship (TActiveRecord::BELONGS_TO) between
+ * the source objects and the related foreign object. Consider the
* <b>entity</b> relationship between a Team and a Player.
* <code>
* +------+ +--------+
@@ -38,17 +38,19 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* public $team_name; //foreign key player.team_name <-> team.name
* public $age;
* public $team; //foreign object TeamRecord
- *
- * protected static $RELATIONS = array(
- * 'team' => array(self::BELONGS_TO, 'TeamRecord'));
- *
+ *
+ * protected static $RELATIONS = array
+ * (
+ * 'team' => array(self::BELONGS_TO, 'TeamRecord')
+ * );
+ *
* public static function finder($className=__CLASS__)
* {
* return parent::finder($className);
* }
* }
* </code>
- * The <tt>$RELATIONS</tt> static property of PlayerRecord defines that the
+ * The static <tt>$RELATIONS</tt> property of PlayerRecord defines that the
* property <tt>$team</tt> belongs to (or is a) <tt>TeamRecord</tt>s.
*
* The team object may be fetched as follows.
@@ -58,7 +60,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* The method <tt>with_xxx()</tt> (where <tt>xxx</tt> is the relationship property
* name, in this case, <tt>team</tt>) fetchs the corresponding TeamRecords using
* a second query (not by using a join). The <tt>with_xxx()</tt> accepts the same
- * arguments as other finder methods of TActiveRecord, e.g.
+ * arguments as other finder methods of TActiveRecord, e.g.
* <tt>with_team('location = ?', 'Madrid')</tt>.
*
* @author Wei Zhuo <weizho[at]gmail[dot]com>
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php
index 795630ab..c5ce616e 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasMany.php
@@ -34,8 +34,10 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
*
* public $players=array(); //list of players
*
- * protected static $RELATIONS=array(
- * 'players' => array(self::HAS_MANY, 'PlayerRecord'));
+ * protected static $RELATIONS=array
+ * (
+ * 'players' => array(self::HAS_MANY, 'PlayerRecord')
+ * );
*
* public static function finder($className=__CLASS__)
* {
@@ -47,7 +49,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* // see TActiveRecordBelongsTo for detailed definition
* }
* </code>
- * The <tt>$RELATIONS</tt> static property of TeamRecord defines that the
+ * The static <tt>$RELATIONS</tt> property of TeamRecord defines that the
* property <tt>$players</tt> has many <tt>PlayerRecord</tt>s.
*
* The players list may be fetched as follows.
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php
index 456848fe..50558a2b 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasManyAssociation.php
@@ -1,16 +1,98 @@
<?php
+/**
+ * TActiveRecordHasManyAssociation class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2007 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Data.ActiveRecord.Relations
+ */
/**
* Loads base active record relations class.
*/
Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
+/**
+ * Implements the M-N (many to many) relationship via association table.
+ * Consider the <b>entity</b> relationship between Articles and Categories
+ * via the association table <tt>Article_Category</tt>.
+ * <code>
+ * +---------+ +------------------+ +----------+
+ * | Article | * -----> * | Article_Category | * <----- * | Category |
+ * +---------+ +------------------+ +----------+
+ * </code>
+ * Where one article may have 0 or more categories and each category may have 0
+ * or more articles. We may model Article-Category <b>object</b> relationship
+ * as active record as follows.
+ * <code>
+ * class ArticleRecord
+ * {
+ * const TABLE='Article';
+ * public $article_id;
+ *
+ * public $Categories=array(); //foreign object collection.
+ *
+ * protected static $RELATIONS = array
+ * (
+ * 'Categories' => array(self::HAS_MANY, 'CategoryRecord', 'Article_Category')
+ * );
+ *
+ * public static function finder($className=__CLASS__)
+ * {
+ * return parent::finder($className);
+ * }
+ * }
+ * class CategoryRecord
+ * {
+ * const TABLE='Category';
+ * public $category_id;
+ *
+ * public $Articles=array();
+ *
+ * protected static $RELATIONS = array
+ * (
+ * 'Articles' => array(self::HAS_MANY, 'ArticleRecord', 'Article_Category')
+ * );
+ *
+ * public static function finder($className=__CLASS__)
+ * {
+ * return parent::finder($className);
+ * }
+ * }
+ * </code>
+ *
+ * The static <tt>$RELATIONS</tt> property of ArticleRecord defines that the
+ * property <tt>$Categories</tt> has many <tt>CategoryRecord</tt>s. Similar, the
+ * static <tt>$RELATIONS</tt> property of CategoryRecord defines many ArticleRecords.
+ *
+ * The articles with categories list may be fetched as follows.
+ * <code>
+ * $articles = TeamRecord::finder()->withCategories()->findAll();
+ * </code>
+ * The method <tt>with_xxx()</tt> (where <tt>xxx</tt> is the relationship property
+ * name, in this case, <tt>Categories</tt>) fetchs the corresponding CategoryRecords using
+ * a second query (not by using a join). The <tt>with_xxx()</tt> accepts the same
+ * arguments as other finder methods of TActiveRecord.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Data.ActiveRecord.Relations
+ * @since 3.1
+ */
class TActiveRecordHasManyAssociation extends TActiveRecordRelation
{
private $_association;
private $_sourceTable;
private $_foreignTable;
+ /**
+ * Get the foreign key index values from the results and make calls to the
+ * database to find the corresponding foreign objects using association table.
+ * @param array original results.
+ */
protected function collectForeignObjects(&$results)
{
$association = $this->getAssociationTable();
@@ -26,6 +108,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
$this->fetchForeignObjects($results, $foreignKeys,$indexValues,$sourceKeys);
}
+ /**
+ * @return TDbTableInfo association table information.
+ */
protected function getAssociationTable()
{
if($this->_association===null)
@@ -38,6 +123,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
return $this->_association;
}
+ /**
+ * @return TDbTableInfo source table information.
+ */
protected function getSourceTable()
{
if($this->_sourceTable===null)
@@ -48,6 +136,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
return $this->_sourceTable;
}
+ /**
+ * @return TDbTableInfo foreign table information.
+ */
protected function getForeignTable()
{
if($this->_foreignTable===null)
@@ -59,6 +150,9 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
return $this->_foreignTable;
}
+ /**
+ * @return TDbCommandBuilder
+ */
protected function getCommandBuilder()
{
return $this->getSourceRecord()->getRecordGateway()->getCommand($this->getSourceRecord());
@@ -117,6 +211,10 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
return $command;
}
+ /**
+ * @param array source table column names.
+ * @return string comma separated source column names.
+ */
protected function getSourceColumns($sourceKeys)
{
$columns=array();
@@ -127,6 +225,13 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
return implode(', ', $columns);
}
+ /**
+ * SQL inner join for M-N relationship via association table.
+ * @param array foreign table column key names.
+ * @param array source table index values.
+ * @param array source table column names.
+ * @return string inner join condition for M-N relationship via association table.
+ */
protected function getAssociationJoin($foreignKeys,$indexValues,$sourceKeys)
{
$refInfo= $this->getAssociationTable();
@@ -143,9 +248,7 @@ class TActiveRecordHasManyAssociation extends TActiveRecordRelation
$joins[] = "{$fkTable}.{$fkField} = {$refTable}.{$refField}";
}
$joinCondition = implode(' AND ', $joins);
-
$index = $this->getCommandBuilder()->getIndexKeyCondition($refInfo,array_keys($sourceKeys), $indexValues);
-
return "INNER JOIN {$refTable} ON ({$joinCondition}) AND {$index}";
}
}
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php
index 4286254b..6348f16b 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordHasOne.php
@@ -21,7 +21,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* related to the source object. The HAS_ONE relation is very similar to the
* HAS_MANY relationship (in fact, it is equivalent in the entities relationship point of view).
*
- * The difference of HAS_ONE from HAS_MANY is that the foreign object is singular.
+ * The difference of HAS_ONE from HAS_MANY is that the foreign object is singular.
* That is, HAS_MANY will return a collection of records while HAS_ONE returns the
* corresponding record.
*
@@ -32,7 +32,7 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* +-----+ +--------+
* </code>
* Where each engine belongs to only one car, that is, the Engine entity has
- * a foreign key to the Car's primary key. We may model
+ * a foreign key to the Car's primary key. We may model
* Engine-Car <b>object</b> relationship as active record as follows.
* <code>
* class CarRecord extends TActiveRecord
@@ -43,8 +43,10 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
*
* public $engine; //engine foreign object
*
- * protected static $RELATIONS=array(
- * 'engine' => array(self::HAS_ONE, 'EngineRecord'));
+ * protected static $RELATIONS=array
+ * (
+ * 'engine' => array(self::HAS_ONE, 'EngineRecord')
+ * );
*
* public static function finder($className=__CLASS__)
* {
@@ -57,14 +59,14 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelation');
* public $engine_id;
* public $capacity;
* public $car_id; //foreign key to cars
- *
+ *
* public static function finder($className=__CLASS__)
* {
* return parent::finder($className);
* }
* }
* </code>
- * The <tt>$RELATIONS</tt> static property of CarRecord defines that the
+ * The static <tt>$RELATIONS</tt> property of CarRecord defines that the
* property <tt>$engine</tt> that will reference an <tt>EngineRecord</tt> instance.
*
* The car record with engine property list may be fetched as follows.
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
index 38455309..46609095 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelation.php
@@ -18,8 +18,6 @@ Prado::using('System.Data.ActiveRecord.Relations.TActiveRecordRelationContext');
/**
* Base class for active record relationships.
*
- * description
- *
* @author Wei Zhuo <weizho[at]gmail[dot]com>
* @version $Id$
* @package System.Data.ActiveRecord.Relations
@@ -66,7 +64,7 @@ abstract class TActiveRecordRelation
static $stack=array();
$results = call_user_func_array(array($this->getSourceRecord(),$method),$args);
- if(is_array($results) || $results instanceof TActiveRecord)
+ if(is_array($results) || $results instanceof ArrayAccess || $results instanceof TActiveRecord)
{
$this->collectForeignObjects($results);
while($obj = array_pop($stack))
@@ -134,8 +132,9 @@ abstract class TActiveRecordRelation
*/
protected function getIndexValues($keys, $results)
{
- if(!is_array($results))
+ if(!is_array($results) && !$results instanceof ArrayAccess)
$results = array($results);
+ $values=array();
foreach($results as $result)
{
$value = array();
@@ -169,7 +168,7 @@ abstract class TActiveRecordRelation
*/
protected function setResultCollection(&$results, &$collections, $properties)
{
- if(is_array($results))
+ if(is_array($results) || $results instanceof ArrayAccess)
{
for($i=0,$k=count($results);$i<$k;$i++)
$this->setObjectProperty($results[$i], $properties, $collections);
@@ -191,5 +190,5 @@ abstract class TActiveRecordRelation
$source->{$prop} = isset($collections[$hash]) ? $collections[$hash] : array();
}
}
-
+
?> \ No newline at end of file
diff --git a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php
index 033d7638..167c90a5 100644
--- a/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php
+++ b/framework/Data/ActiveRecord/Relations/TActiveRecordRelationContext.php
@@ -57,11 +57,14 @@ class TActiveRecordRelationContext
if(!isset($statics[self::RELATIONS_CONST]))
throw new TActiveRecordException('ar_relations_undefined',
get_class($this->_sourceRecord), self::RELATIONS_CONST);
- if(isset($statics[self::RELATIONS_CONST][$property]))
- return $statics[self::RELATIONS_CONST][$property];
- else
- throw new TActiveRecordException('ar_undefined_relation_prop',
- $property, get_class($this->_sourceRecord), self::RELATIONS_CONST);
+ $property = strtolower($property);
+ foreach($statics[self::RELATIONS_CONST] as $name => $relation)
+ {
+ if(strtolower($name)===$property)
+ return $relation;
+ }
+ throw new TActiveRecordException('ar_undefined_relation_prop',
+ $property, get_class($this->_sourceRecord), self::RELATIONS_CONST);
}
/**
diff --git a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php
index e1d57124..84c381f0 100644
--- a/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php
+++ b/framework/Data/ActiveRecord/Scaffold/InputBuilder/TScaffoldInputCommon.php
@@ -190,6 +190,7 @@ class TScaffoldInputCommon extends TScaffoldInputBase
{
$value = $this->getRecordPropertyValue($column, $record);
$control = new TDatePicker();
+ $control->setFromYear(1900);
$control->setInputMode(TDatePickerInputMode::DropDownList);
$control->setDateFormat('yyyy-MM-dd');
if(!empty($value))
diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php
index 71dc83cd..34f8a592 100644
--- a/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php
+++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldListView.php
@@ -51,16 +51,6 @@ Prado::using('System.Data.ActiveRecord.Scaffold.TScaffoldBase');
class TScaffoldListView extends TScaffoldBase
{
/**
- * Initialize the sort drop down list in non post back mode (i.e. GET requests).
- */
- public function onLoad($param)
- {
- parent::onLoad($param);
- if(!$this->getPage()->getIsPostBack())
- $this->initializeSort();
- }
-
- /**
* Initialize the sort drop down list and the column names repeater.
*/
protected function initializeSort()
@@ -87,6 +77,8 @@ class TScaffoldListView extends TScaffoldBase
public function onPreRender($param)
{
parent::onPreRender($param);
+ if(!$this->getPage()->getIsPostBack())
+ $this->initializeSort();
$this->loadRecordData();
}
@@ -113,8 +105,10 @@ class TScaffoldListView extends TScaffoldBase
if($offset + $limit > $total)
$limit = $total - $offset;
$criteria = new TActiveRecordCriteria($this->getSearchCondition(), $this->getSearchParameters());
- $criteria->setLimit($limit);
- $criteria->setOffset($offset);
+ if($limit > 0)
+ $criteria->setLimit($limit);
+ if($offset <= $total)
+ $criteria->setOffset($offset);
$order = explode(' ',$this->_sort->getSelectedValue(), 2);
if(is_array($order) && count($order) === 2)
$criteria->OrdersBy[$order[0]] = $order[1];
diff --git a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php
index c144fe37..ad7ba55d 100644
--- a/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php
+++ b/framework/Data/ActiveRecord/Scaffold/TScaffoldView.php
@@ -44,9 +44,9 @@ class TScaffoldView extends TScaffoldBase
/**
* Copy basic record details to the list/edit/search controls.
*/
- public function onLoad($param)
+ public function onPreRender($param)
{
- parent::onLoad($param);
+ parent::onPreRender($param);
$this->getListView()->copyFrom($this);
$this->getEditView()->copyFrom($this);
$this->getSearchControl()->copyFrom($this);
diff --git a/framework/Data/ActiveRecord/TActiveRecord.php b/framework/Data/ActiveRecord/TActiveRecord.php
index cb3a1ebe..479f643b 100644
--- a/framework/Data/ActiveRecord/TActiveRecord.php
+++ b/framework/Data/ActiveRecord/TActiveRecord.php
@@ -328,6 +328,7 @@ abstract class TActiveRecord extends TComponent
/**
* @param TDbDataReader data reader
+ * @return array
*/
protected function collectObjects($reader)
{
diff --git a/framework/Data/Common/Mssql/TMssqlCommandBuilder.php b/framework/Data/Common/Mssql/TMssqlCommandBuilder.php
index b22c08a5..3de6aa5e 100644
--- a/framework/Data/Common/Mssql/TMssqlCommandBuilder.php
+++ b/framework/Data/Common/Mssql/TMssqlCommandBuilder.php
@@ -1,6 +1,6 @@
<?php
/**
- * TDbCommandBuilder class file.
+ * TMsssqlCommandBuilder class file.
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @link http://www.pradosoft.com/
@@ -13,8 +13,8 @@
Prado::using('System.Data.Common.TDbCommandBuilder');
/**
- * TDbCommandBuilder provides basic methods to create query commands for tables
- * giving by {@link setTableInfo TableInfo} the property.
+ * TMssqlCommandBuilder provides specifics methods to create limit/offset query commands
+ * for MSSQL servers.
*
* @author Wei Zhuo <weizho[at]gmail[dot]com>
* @version $Id: TDbCommandBuilder.php 1863 2007-04-12 12:43:49Z wei $
diff --git a/framework/Data/Common/Mssql/TMssqlTableInfo.php b/framework/Data/Common/Mssql/TMssqlTableInfo.php
index e408440b..ee9c500b 100644
--- a/framework/Data/Common/Mssql/TMssqlTableInfo.php
+++ b/framework/Data/Common/Mssql/TMssqlTableInfo.php
@@ -60,7 +60,6 @@ class TMssqlTableInfo extends TDbTableInfo
Prado::using('System.Data.Common.Mssql.TMssqlCommandBuilder');
return new TMssqlCommandBuilder($connection,$this);
}
-
}
?> \ No newline at end of file
diff --git a/framework/Data/Common/Sqlite/TSqliteCommandBuilder.php b/framework/Data/Common/Sqlite/TSqliteCommandBuilder.php
new file mode 100644
index 00000000..9f1253c9
--- /dev/null
+++ b/framework/Data/Common/Sqlite/TSqliteCommandBuilder.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * TSqliteCommandBuilder class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2007 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TDbCommandBuilder.php 1863 2007-04-12 12:43:49Z wei $
+ * @package System.Data.Common
+ */
+
+Prado::using('System.Data.Common.TDbCommandBuilder');
+
+/**
+ * TSqliteCommandBuilder provides specifics methods to create limit/offset query commands
+ * for Sqlite database.
+ *
+ * @author Wei Zhuo <weizho[at]gmail[dot]com>
+ * @version $Id: TDbCommandBuilder.php 1863 2007-04-12 12:43:49Z wei $
+ * @package System.Data.Common
+ * @since 3.1
+ */
+class TSqliteCommandBuilder extends TDbCommandBuilder
+{
+ /**
+ * Alters the sql to apply $limit and $offset.
+ * @param string SQL query string.
+ * @param integer maximum number of rows, -1 to ignore limit.
+ * @param integer row offset, -1 to ignore offset.
+ * @return string SQL with limit and offset.
+ */
+ public function applyLimitOffset($sql, $limit=-1, $offset=-1)
+ {
+ $limit = $limit!==null ? intval($limit) : -1;
+ $offset = $offset!==null ? intval($offset) : -1;
+ if($limit > 0 || $offset > 0)
+ {
+ $limitStr = ' LIMIT '.$limit;
+ $offsetStr = $offset >= 0 ? ' OFFSET '.$offset : '';
+ return $sql.$limitStr.$offsetStr;
+ }
+ else
+ return $sql;
+ }
+}
+
+?> \ No newline at end of file
diff --git a/framework/Data/Common/Sqlite/TSqliteMetaData.php b/framework/Data/Common/Sqlite/TSqliteMetaData.php
index f9b49488..6c6ff232 100644
--- a/framework/Data/Common/Sqlite/TSqliteMetaData.php
+++ b/framework/Data/Common/Sqlite/TSqliteMetaData.php
@@ -49,7 +49,7 @@ class TSqliteMetaData extends TDbMetaData
if($column->getIsPrimaryKey())
$primary[] = $col['name'];
}
- $info['TableName'] = $tableName;
+ $info['TableName'] = $table;
if($this->getIsView($tableName))
$info['IsView'] = true;
if(count($columns)===0)
diff --git a/framework/Data/Common/Sqlite/TSqliteTableInfo.php b/framework/Data/Common/Sqlite/TSqliteTableInfo.php
index 1581c3cc..e0bcb484 100644
--- a/framework/Data/Common/Sqlite/TSqliteTableInfo.php
+++ b/framework/Data/Common/Sqlite/TSqliteTableInfo.php
@@ -26,6 +26,15 @@ Prado::using('System.Data.Common.Sqlite.TSqliteTableColumn');
*/
class TSqliteTableInfo extends TDbTableInfo
{
+ /**
+ * @param TDbConnection database connection.
+ * @return TDbCommandBuilder new command builder
+ */
+ public function createCommandBuilder($connection)
+ {
+ Prado::using('System.Data.Common.Sqlite.TSqliteCommandBuilder');
+ return new TSqliteCommandBuilder($connection,$this);
+ }
}
?> \ No newline at end of file
diff --git a/framework/Data/Common/TDbCommandBuilder.php b/framework/Data/Common/TDbCommandBuilder.php
index 440d579d..3535100f 100644
--- a/framework/Data/Common/TDbCommandBuilder.php
+++ b/framework/Data/Common/TDbCommandBuilder.php
@@ -117,37 +117,38 @@ class TDbCommandBuilder extends TComponent
}
/**
- * NOT SAFE YET!
+ * Computes the SQL condition for search a set of column using regular expression
+ * (or LIKE, depending on database implementation) to match a string of
+ * keywords (default matches all keywords).
+ * @param array list of column id for potential search condition.
+ * @param string string of keywords
+ * @return string SQL search condition matching on a set of columns.
*/
public function getSearchExpression($fields, $keywords)
{
if(strlen(trim($keywords)) == 0) return '';
- $words = preg_split('/\s/', preg_quote($keywords, '\''));
- $result = array();
+ $words = preg_split('/\s/u', $keywords);
+ $conditions = array();
foreach($fields as $field)
{
$column = $this->getTableInfo()->getColumn($field)->getColumnName();
- $result[] = $this->getRegexpCriteriaStr($column, $words);
+ $conditions[] = $this->getSearchCondition($column, $words);
}
- return '('.implode(' OR ', $result).')';
- }
-
- protected function getRegexpCriteriaStr($column, $words)
- {
- $regexp = implode('|', $words);
- return "({$column} REGEXP '{$regexp}')";
+ return '('.implode(' OR ', $conditions).')';
}
/**
- * Computes the SQL condition for search a set of column using regular expression
- * to match a string of keywords. The implementation should only uses columns
- * that permit regular expression matching. This method should be implemented in
- * database specific command builder classes.
- * @param array list of column id for potential search condition.
- * @param string string of keywords
- * @return string SQL condition for regular expression matching on a set of columns.
+ * @param string column name.
+ * @param array keywords
+ * @return string search condition for all words in one column.
*/
- //abstract public function createRegExpSearch($columnIds, $keywords);
+ protected function getSearchCondition($column, $words)
+ {
+ $conditions=array();
+ foreach($words as $word)
+ $conditions[] = $column.' LIKE '.$this->getDbConnection()->quoteString('%'.$word.'%');
+ return '('.implode(' AND ', $conditions).')';
+ }
/**
* Appends the $where condition to the string "SELECT * FROM tableName WHERE ".
diff --git a/framework/prado-cli.php b/framework/prado-cli.php
index ca3e1461..3839e816 100755
--- a/framework/prado-cli.php
+++ b/framework/prado-cli.php
@@ -691,7 +691,6 @@ class PradoCommandLineActiveRecordGen extends PradoCommandLineAction
{
$prop .= <<<EOD
-
/**
* @var $type $name
* @soapproperty
@@ -699,13 +698,13 @@ class PradoCommandLineActiveRecordGen extends PradoCommandLineAction
EOD;
}
- $prop .= "\tpublic $name;\n";
+ $prop .= "\tpublic $name;";
return $prop;
}
protected function generateClass($properties, $tablename, $class)
{
- $props = implode("\n", $properties);
+ $props = implode("\x0D\x0A", $properties);
$date = date('Y-m-d h:i:s');
return <<<EOD
<?php
diff --git a/tests/FunctionalTests/tickets/protected/pages/Ticket614.page b/tests/FunctionalTests/tickets/protected/pages/Ticket614.page
new file mode 100644
index 00000000..0b1901ea
--- /dev/null
+++ b/tests/FunctionalTests/tickets/protected/pages/Ticket614.page
@@ -0,0 +1,13 @@
+<com:TContent ID="Content">
+
+<com:TTextBox ID="text1" />
+<com:TRegularExpressionValidator
+ ID="validator1"
+ ControlToValidate="text1"
+ ErrorMessage="*"
+ PatternModifiers="u"
+ RegularExpression="[\x0400-\x04FF ]{2,60}" />
+
+<com:TButton ID="button1" Text="Submit!"/>
+
+</com:TContent> \ No newline at end of file