From c7d41e5bea4a5f96979a08da9cc9f79355edfe70 Mon Sep 17 00:00:00 2001
From: wei <>
Date: Sun, 16 Jul 2006 06:19:36 +0000
Subject: Update Time Tracker demo.
---
.gitattributes | 51 ++--
buildscripts/texbuilder/quickstart/build.php | 2 +-
buildscripts/texbuilder/sqlmap/build.php | 2 +-
buildscripts/texbuilder/sqlmap/pages.php | 6 +-
buildscripts/texbuilder/time-tracker/db.vsd | Bin 102912 -> 102912 bytes
buildscripts/texbuilder/time-tracker/pages.php | 18 +-
.../texbuilder/time-tracker/time-tracker.tex | 11 +
demos/sqlmap/protected/APP_CODE/Person.php | 26 ++
demos/sqlmap/protected/application.xml | 17 +-
demos/sqlmap/protected/business-objects/Person.php | 26 --
demos/sqlmap/protected/controls/Layout.php | 7 -
demos/sqlmap/protected/controls/Layout.tpl | 45 ----
demos/sqlmap/protected/controls/TopicList.php | 8 -
demos/sqlmap/protected/controls/TopicList.tpl | 66 -----
demos/sqlmap/protected/pages/Home.page | 1 -
demos/sqlmap/protected/pages/Manual/Layout.php | 7 +
demos/sqlmap/protected/pages/Manual/Layout.tpl | 45 ++++
demos/sqlmap/protected/pages/Manual/Overview.page | 10 +-
demos/sqlmap/protected/pages/Manual/TopicList.php | 8 +
demos/sqlmap/protected/pages/Manual/TopicList.tpl | 66 +++++
.../protected/pages/Manual/Tutorial/TestAgain.page | 214 ++++++++++++++++
.../protected/pages/Manual/Tutorial/TestFirst.page | 238 +++++++++++++++++
.../pages/Manual/Tutorial/TestSecond.page | 116 +++++++++
.../protected/pages/Manual/Tutorial/example1.png | Bin 0 -> 236887 bytes
.../protected/pages/Manual/Tutorial/grid1.png | Bin 0 -> 275250 bytes
.../protected/pages/Manual/Tutorial/grid2.png | Bin 0 -> 218210 bytes
.../sqlmap/protected/pages/Tutorial/TestAgain.page | 214 ----------------
.../sqlmap/protected/pages/Tutorial/TestFirst.page | 238 -----------------
.../protected/pages/Tutorial/TestSecond.page | 116 ---------
demos/sqlmap/protected/pages/Tutorial/example1.png | Bin 236887 -> 0 bytes
demos/sqlmap/protected/pages/Tutorial/grid1.png | Bin 275250 -> 0 bytes
demos/sqlmap/protected/pages/Tutorial/grid2.png | Bin 218210 -> 0 bytes
demos/sqlmap/protected/pages/config.xml | 8 -
demos/time-tracker/protected/APP_CODE/BaseDao.php | 27 ++
.../time-tracker/protected/APP_CODE/DaoManager.php | 126 +++++++++
demos/time-tracker/protected/APP_CODE/Project.php | 18 ++
.../time-tracker/protected/APP_CODE/ProjectDao.php | 23 +-
.../protected/APP_CODE/TimeTrackerException.php | 19 ++
.../protected/APP_CODE/TimeTrackerUser.php | 51 ++--
.../APP_CODE/TimeTrackerUserTypeHandler.php | 54 ++++
demos/time-tracker/protected/APP_CODE/UserDao.php | 155 +++++++++++
.../protected/APP_CODE/UserManager.php | 68 +++++
.../time-tracker/protected/APP_CODE/exceptions.txt | 6 +-
.../protected/App_Data/time_tracker.db | Bin 0 -> 16384 bytes
demos/time-tracker/protected/data/time_tracker.db | Bin 16384 -> 0 bytes
.../protected/pages/Docs/TopicList.tpl | 2 +-
.../protected/pages/Docs/WritingUnitTest.page | 43 ++--
demos/time-tracker/protected/pages/Docs/config.xml | 12 +-
demos/time-tracker/protected/pages/Docs/db.png | Bin 26879 -> 26521 bytes
.../protected/pages/TimeTracker/Login.page | 38 +++
.../protected/pages/TimeTracker/Login.php | 53 ++++
.../protected/pages/TimeTracker/Logout.page | 0
.../protected/pages/TimeTracker/Logout.php | 34 +++
.../protected/pages/TimeTracker/MainLayout.php | 7 +
.../protected/pages/TimeTracker/MainLayout.tpl | 40 +++
.../protected/pages/TimeTracker/SiteMap.php | 8 +
.../protected/pages/TimeTracker/SiteMap.tpl | 43 ++++
.../protected/pages/TimeTracker/UserCreate.page | 65 +++++
.../protected/pages/TimeTracker/UserCreate.php | 78 ++++++
.../protected/pages/TimeTracker/UserList.page | 3 +
.../protected/pages/TimeTracker/config.xml | 24 ++
demos/time-tracker/protected/pages/Welcome.page | 168 ++++++++++++
demos/time-tracker/tests/functional.php | 2 +-
demos/time-tracker/tests/unit.php | 2 +-
.../tests/unit/AddUserToProjectTestCase.php | 35 ---
demos/time-tracker/tests/unit/BaseTestCase.php | 35 +++
.../tests/unit/CreateNewProjectTestCase.php | 90 -------
.../time-tracker/tests/unit/ProjectDaoTestCase.php | 92 -------
demos/time-tracker/tests/unit/ProjectTestCase.php | 6 +-
demos/time-tracker/tests/unit/UserDaoTestCase.php | 283 +++++++++++++++++++++
.../time-tracker/themes/TimeTracker/background.png | Bin 0 -> 4674 bytes
demos/time-tracker/themes/TimeTracker/site.css | 217 ++++++++++++++++
demos/time-tracker/themes/TimeTracker/tabs.png | Bin 0 -> 324 bytes
.../SQLMap/Configuration/TConfigDeserialize.php | 1 +
.../SQLMap/Configuration/TDomSqlMapBuilder.php | 52 +++-
.../SQLMap/Configuration/TParameterMap.php | 2 +-
.../DataAccess/SQLMap/Configuration/TResultMap.php | 22 +-
.../SQLMap/Configuration/TSqlMapStatement.php | 8 +-
.../SQLMap/DataMapper/TPropertyAccess.php | 6 +-
.../SQLMap/DataMapper/TTypeHandlerFactory.php | 10 +-
.../DataAccess/SQLMap/DataMapper/messages.txt | 13 +-
.../SQLMap/Statements/TInsertMappedStatement.php | 8 +-
.../SQLMap/Statements/TMappedStatement.php | 60 +++--
.../SQLMap/Statements/TSelectMappedStatement.php | 4 +-
.../SQLMap/Statements/TUpdateMappedStatement.php | 8 +-
tests/unit/SQLMap/BaseTest.php | 6 +-
tests/unit/SQLMap/InheritanceTest.php | 2 +-
tests/unit/SQLMap/sqlite/tests.db | Bin 32768 -> 32768 bytes
88 files changed, 2605 insertions(+), 1090 deletions(-)
create mode 100644 demos/sqlmap/protected/APP_CODE/Person.php
delete mode 100644 demos/sqlmap/protected/business-objects/Person.php
delete mode 100644 demos/sqlmap/protected/controls/Layout.php
delete mode 100644 demos/sqlmap/protected/controls/Layout.tpl
delete mode 100644 demos/sqlmap/protected/controls/TopicList.php
delete mode 100644 demos/sqlmap/protected/controls/TopicList.tpl
delete mode 100644 demos/sqlmap/protected/pages/Home.page
create mode 100644 demos/sqlmap/protected/pages/Manual/Layout.php
create mode 100644 demos/sqlmap/protected/pages/Manual/Layout.tpl
create mode 100644 demos/sqlmap/protected/pages/Manual/TopicList.php
create mode 100644 demos/sqlmap/protected/pages/Manual/TopicList.tpl
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/example1.png
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png
create mode 100644 demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/TestAgain.page
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/TestFirst.page
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/TestSecond.page
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/example1.png
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/grid1.png
delete mode 100644 demos/sqlmap/protected/pages/Tutorial/grid2.png
delete mode 100644 demos/sqlmap/protected/pages/config.xml
create mode 100644 demos/time-tracker/protected/APP_CODE/DaoManager.php
create mode 100644 demos/time-tracker/protected/APP_CODE/TimeTrackerUserTypeHandler.php
create mode 100644 demos/time-tracker/protected/APP_CODE/UserDao.php
create mode 100644 demos/time-tracker/protected/APP_CODE/UserManager.php
create mode 100644 demos/time-tracker/protected/App_Data/time_tracker.db
delete mode 100644 demos/time-tracker/protected/data/time_tracker.db
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/Login.page
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/Login.php
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/Logout.page
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/Logout.php
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/MainLayout.php
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/MainLayout.tpl
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/SiteMap.php
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/UserCreate.page
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/UserCreate.php
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/UserList.page
create mode 100644 demos/time-tracker/protected/pages/TimeTracker/config.xml
create mode 100644 demos/time-tracker/protected/pages/Welcome.page
delete mode 100644 demos/time-tracker/tests/unit/AddUserToProjectTestCase.php
create mode 100644 demos/time-tracker/tests/unit/BaseTestCase.php
delete mode 100644 demos/time-tracker/tests/unit/CreateNewProjectTestCase.php
delete mode 100644 demos/time-tracker/tests/unit/ProjectDaoTestCase.php
create mode 100644 demos/time-tracker/tests/unit/UserDaoTestCase.php
create mode 100644 demos/time-tracker/themes/TimeTracker/background.png
create mode 100644 demos/time-tracker/themes/TimeTracker/site.css
create mode 100644 demos/time-tracker/themes/TimeTracker/tabs.png
diff --git a/.gitattributes b/.gitattributes
index 3127d88f..6cdc6483 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1011,13 +1011,8 @@ demos/soap/protected/pages/Home.php -text
demos/soap/protected/webservices/SimpleService.php -text
demos/sqlmap/index.php -text
demos/sqlmap/protected/.htaccess -text
+demos/sqlmap/protected/APP_CODE/Person.php -text
demos/sqlmap/protected/application.xml -text
-demos/sqlmap/protected/business-objects/Person.php -text
-demos/sqlmap/protected/controls/Layout.php -text
-demos/sqlmap/protected/controls/Layout.tpl -text
-demos/sqlmap/protected/controls/TopicList.php -text
-demos/sqlmap/protected/controls/TopicList.tpl -text
-demos/sqlmap/protected/pages/Home.page -text
demos/sqlmap/protected/pages/Manual/BigPicture.page -text
demos/sqlmap/protected/pages/Manual/BuildingTSqlMapper.page -text
demos/sqlmap/protected/pages/Manual/CacheModels.page -text
@@ -1033,6 +1028,8 @@ demos/sqlmap/protected/pages/Manual/ImplicitResultMaps.page -text
demos/sqlmap/protected/pages/Manual/InheritanceMapping.page -text
demos/sqlmap/protected/pages/Manual/InlineParameterMaps.page -text
demos/sqlmap/protected/pages/Manual/Installing.page -text
+demos/sqlmap/protected/pages/Manual/Layout.php -text
+demos/sqlmap/protected/pages/Manual/Layout.tpl -text
demos/sqlmap/protected/pages/Manual/MappedStatements.page -text
demos/sqlmap/protected/pages/Manual/Overview.page -text
demos/sqlmap/protected/pages/Manual/ParameterMap.page -text
@@ -1040,6 +1037,14 @@ demos/sqlmap/protected/pages/Manual/ResultMapAttributes.page -text
demos/sqlmap/protected/pages/Manual/ResultMaps.page -text
demos/sqlmap/protected/pages/Manual/StatementElementAttributes.page -text
demos/sqlmap/protected/pages/Manual/TheSQL.page -text
+demos/sqlmap/protected/pages/Manual/TopicList.php -text
+demos/sqlmap/protected/pages/Manual/TopicList.tpl -text
+demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page -text
+demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page -text
+demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page -text
+demos/sqlmap/protected/pages/Manual/Tutorial/example1.png -text
+demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png -text
+demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png -text
demos/sqlmap/protected/pages/Manual/WorkingWithDataMaps.page -text
demos/sqlmap/protected/pages/Manual/diagram.png -text
demos/sqlmap/protected/pages/Sample/Home.page -text
@@ -1049,22 +1054,19 @@ demos/sqlmap/protected/pages/Sample/crud1.page -text
demos/sqlmap/protected/pages/Sample/crud1.php -text
demos/sqlmap/protected/pages/Sample/crud2.page -text
demos/sqlmap/protected/pages/Sample/crud2.php -text
-demos/sqlmap/protected/pages/Tutorial/TestAgain.page -text
-demos/sqlmap/protected/pages/Tutorial/TestFirst.page -text
-demos/sqlmap/protected/pages/Tutorial/TestSecond.page -text
-demos/sqlmap/protected/pages/Tutorial/example1.png -text
-demos/sqlmap/protected/pages/Tutorial/grid1.png -text
-demos/sqlmap/protected/pages/Tutorial/grid2.png -text
-demos/sqlmap/protected/pages/config.xml -text
demos/time-tracker/index.php -text
demos/time-tracker/protected/.htaccess -text
demos/time-tracker/protected/APP_CODE/BaseDao.php -text
+demos/time-tracker/protected/APP_CODE/DaoManager.php -text
demos/time-tracker/protected/APP_CODE/Project.php -text
demos/time-tracker/protected/APP_CODE/ProjectDao.php -text
demos/time-tracker/protected/APP_CODE/TimeTrackerException.php -text
demos/time-tracker/protected/APP_CODE/TimeTrackerUser.php -text
+demos/time-tracker/protected/APP_CODE/TimeTrackerUserTypeHandler.php -text
+demos/time-tracker/protected/APP_CODE/UserDao.php -text
+demos/time-tracker/protected/APP_CODE/UserManager.php -text
demos/time-tracker/protected/APP_CODE/exceptions.txt -text
-demos/time-tracker/protected/data/time_tracker.db -text
+demos/time-tracker/protected/App_Data/time_tracker.db -text
demos/time-tracker/protected/pages/Docs/CreateBusinessCode.page -text
demos/time-tracker/protected/pages/Docs/GettingStarted.page -text
demos/time-tracker/protected/pages/Docs/Home.page -text
@@ -1087,13 +1089,28 @@ demos/time-tracker/protected/pages/Docs/project1.png -text
demos/time-tracker/protected/pages/Docs/unit_test1.png -text
demos/time-tracker/protected/pages/Docs/unit_test2.png -text
demos/time-tracker/protected/pages/Docs/unit_test3.png -text
+demos/time-tracker/protected/pages/TimeTracker/Login.page -text
+demos/time-tracker/protected/pages/TimeTracker/Login.php -text
+demos/time-tracker/protected/pages/TimeTracker/Logout.page -text
+demos/time-tracker/protected/pages/TimeTracker/Logout.php -text
+demos/time-tracker/protected/pages/TimeTracker/MainLayout.php -text
+demos/time-tracker/protected/pages/TimeTracker/MainLayout.tpl -text
+demos/time-tracker/protected/pages/TimeTracker/SiteMap.php -text
+demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl -text
+demos/time-tracker/protected/pages/TimeTracker/UserCreate.page -text
+demos/time-tracker/protected/pages/TimeTracker/UserCreate.php -text
+demos/time-tracker/protected/pages/TimeTracker/UserList.page -text
+demos/time-tracker/protected/pages/TimeTracker/config.xml -text
+demos/time-tracker/protected/pages/Welcome.page -text
demos/time-tracker/tests/functional.php -text
demos/time-tracker/tests/functional/HelloPradoTestCase.php -text
demos/time-tracker/tests/unit.php -text
-demos/time-tracker/tests/unit/AddUserToProjectTestCase.php -text
-demos/time-tracker/tests/unit/CreateNewProjectTestCase.php -text
-demos/time-tracker/tests/unit/ProjectDaoTestCase.php -text
+demos/time-tracker/tests/unit/BaseTestCase.php -text
demos/time-tracker/tests/unit/ProjectTestCase.php -text
+demos/time-tracker/tests/unit/UserDaoTestCase.php -text
+demos/time-tracker/themes/TimeTracker/background.png -text
+demos/time-tracker/themes/TimeTracker/site.css -text
+demos/time-tracker/themes/TimeTracker/tabs.png -text
docs/application.xml -text
docs/specs/application.dtd -text
docs/specs/application.xsd -text
diff --git a/buildscripts/texbuilder/quickstart/build.php b/buildscripts/texbuilder/quickstart/build.php
index c0577c8f..79d6d7ec 100644
--- a/buildscripts/texbuilder/quickstart/build.php
+++ b/buildscripts/texbuilder/quickstart/build.php
@@ -8,7 +8,7 @@ $pdfTex = "$pdflatexExec -interaction=nonstopmode -max-print-line=120 %s";
$mainTexFile = dirname(__FILE__).'/quickstart.tex';
//page root location
-$base = realpath(dirname(__FILE__).'/../../demos/quickstart/protected/pages/');
+$base = realpath(dirname(__FILE__).'/../../../demos/quickstart/protected/pages/');
//-------------- END CONFIG ------------------
diff --git a/buildscripts/texbuilder/sqlmap/build.php b/buildscripts/texbuilder/sqlmap/build.php
index 5717c50c..46773390 100644
--- a/buildscripts/texbuilder/sqlmap/build.php
+++ b/buildscripts/texbuilder/sqlmap/build.php
@@ -8,7 +8,7 @@ $pdfTex = "$pdflatexExec -interaction=nonstopmode -max-print-line=120 %s";
$mainTexFile = dirname(__FILE__).'/sqlmap.tex';
//page root location
-$base = realpath(dirname(__FILE__).'/../protected/pages/');
+$base = realpath(dirname(__FILE__).'/../../../demos/sqlmap/protected/pages/');
//-------------- END CONFIG ------------------
diff --git a/buildscripts/texbuilder/sqlmap/pages.php b/buildscripts/texbuilder/sqlmap/pages.php
index 411ebc4c..adf788ff 100644
--- a/buildscripts/texbuilder/sqlmap/pages.php
+++ b/buildscripts/texbuilder/sqlmap/pages.php
@@ -13,9 +13,9 @@ $pages['Installation and Setup'] = array(
);
$pages['SQLMap for PHP Tutorial'] = array(
- 'Tutorial/TestFirst.page',
- 'Tutorial/TestSecond.page',
- 'Tutorial/TestAgain.page'
+ 'Manual/Tutorial/TestFirst.page',
+ 'Manual/Tutorial/TestSecond.page',
+ 'Manual/Tutorial/TestAgain.page'
);
$pages['Using SQLMap DataMapper'] = array(
diff --git a/buildscripts/texbuilder/time-tracker/db.vsd b/buildscripts/texbuilder/time-tracker/db.vsd
index aa32902d..b12bb87b 100644
Binary files a/buildscripts/texbuilder/time-tracker/db.vsd and b/buildscripts/texbuilder/time-tracker/db.vsd differ
diff --git a/buildscripts/texbuilder/time-tracker/pages.php b/buildscripts/texbuilder/time-tracker/pages.php
index ccad934d..5ec3335a 100644
--- a/buildscripts/texbuilder/time-tracker/pages.php
+++ b/buildscripts/texbuilder/time-tracker/pages.php
@@ -1,21 +1,17 @@
_birthDate;
+ }
+
+ public function setBirthDate($value)
+ {
+ $this->_birthDate = $value;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/sqlmap/protected/application.xml b/demos/sqlmap/protected/application.xml
index 7cfb440f..7dcde037 100644
--- a/demos/sqlmap/protected/application.xml
+++ b/demos/sqlmap/protected/application.xml
@@ -1,16 +1,11 @@
-
+
+
+
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/business-objects/Person.php b/demos/sqlmap/protected/business-objects/Person.php
deleted file mode 100644
index ad9da4b3..00000000
--- a/demos/sqlmap/protected/business-objects/Person.php
+++ /dev/null
@@ -1,26 +0,0 @@
-_birthDate;
- }
-
- public function setBirthDate($value)
- {
- $this->_birthDate = $value;
- }
-}
-
-?>
\ No newline at end of file
diff --git a/demos/sqlmap/protected/controls/Layout.php b/demos/sqlmap/protected/controls/Layout.php
deleted file mode 100644
index e612d52d..00000000
--- a/demos/sqlmap/protected/controls/Layout.php
+++ /dev/null
@@ -1,7 +0,0 @@
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/controls/Layout.tpl b/demos/sqlmap/protected/controls/Layout.tpl
deleted file mode 100644
index c62cc046..00000000
--- a/demos/sqlmap/protected/controls/Layout.tpl
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-Home |
-PradoSoft.com |
-PDF Version |
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/controls/TopicList.php b/demos/sqlmap/protected/controls/TopicList.php
deleted file mode 100644
index ce827cc0..00000000
--- a/demos/sqlmap/protected/controls/TopicList.php
+++ /dev/null
@@ -1,8 +0,0 @@
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/controls/TopicList.tpl b/demos/sqlmap/protected/controls/TopicList.tpl
deleted file mode 100644
index 6c7a3e9e..00000000
--- a/demos/sqlmap/protected/controls/TopicList.tpl
+++ /dev/null
@@ -1,66 +0,0 @@
-
-
-
-
Introduction
-
-
-
Installation and Setup
-
-
-
SQLMap for PHP Tutorial
-
-
-
Using SQLMap DataMapper
-
-
-
Working with Data Maps
-
-
-
Parameter Maps and Inline Parameters
-
-
-
Result Maps
-
-
-
Advanced Topics
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Home.page b/demos/sqlmap/protected/pages/Home.page
deleted file mode 100644
index ff226d4e..00000000
--- a/demos/sqlmap/protected/pages/Home.page
+++ /dev/null
@@ -1 +0,0 @@
-Welcome to Prado!
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Layout.php b/demos/sqlmap/protected/pages/Manual/Layout.php
new file mode 100644
index 00000000..e612d52d
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Layout.php
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Layout.tpl b/demos/sqlmap/protected/pages/Manual/Layout.tpl
new file mode 100644
index 00000000..7c47646d
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Layout.tpl
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+Home |
+PradoSoft.com |
+PDF Version |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Overview.page b/demos/sqlmap/protected/pages/Manual/Overview.page
index 694daf68..258be782 100644
--- a/demos/sqlmap/protected/pages/Manual/Overview.page
+++ b/demos/sqlmap/protected/pages/Manual/Overview.page
@@ -34,7 +34,15 @@ material applies to both implementations.
SQLMap PHP Developer Guide.
A Tutorial is also available. We recommend reviewing the Tutorial for your
-platform before reading this Guide.
+platform before reading this Guide.
+
+SQLMap Tutorial
+
+
Support
diff --git a/demos/sqlmap/protected/pages/Manual/TopicList.php b/demos/sqlmap/protected/pages/Manual/TopicList.php
new file mode 100644
index 00000000..ce827cc0
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/TopicList.php
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/TopicList.tpl b/demos/sqlmap/protected/pages/Manual/TopicList.tpl
new file mode 100644
index 00000000..58e6d9ae
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/TopicList.tpl
@@ -0,0 +1,66 @@
+
+
+
+
Introduction
+
+
+
Installation and Setup
+
+
+
SQLMap for PHP Tutorial
+
+
+
Using SQLMap DataMapper
+
+
+
Working with Data Maps
+
+
+
Parameter Maps and Inline Parameters
+
+
+
Result Maps
+
+
+
Advanced Topics
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page b/demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page
new file mode 100644
index 00000000..4adac73b
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page
@@ -0,0 +1,214 @@
+
+Test, test, again ...
+Of course, tweaking the Person List display is not going to be the end of it.
+Clients always want more, and now ours wants to edit, add, or delete records.
+Let's write some tests for these new tasks, as shown in the following.
+
+
+function testPersonUpdate()
+{
+ $expect = "wei";
+ $edited = "Nah";
+
+ //get it;
+ $person = TMapper::instance()->queryForObject("Select", 1);
+
+ //test it
+ $this->assertNotNull($person);
+ $this->assertEqual($expect, $person->FirstName);
+
+ //change it
+ $person->FirstName = $edited;
+ TMapper::instance()->update("Update", $person);
+
+ //get it again
+ $person = TMapper::instance()->queryForObject("Select", 1);
+
+ //test it
+ $this->assertEqual($edited, $person->FirstName);
+
+ //change it back
+ $person->FirstName = $expect;
+ TMapper::instance()->update("Update", $person);
+}
+
+function testPersonDelete()
+{
+ //insert it
+ $person = new Person;
+ $person->ID = -1;
+ TMapper::instance()->insert("Insert", $person);
+
+ //delte it
+ $count = TMapper::instance()->delete("Delete", -1);
+ $this->assertEqual(1, $count);
+}
+
+
+Not the best tests ever written, but for now, they will do :)
+
+To make the new tests work, we'll need some new mapping statements.
+The following sample shows the complete mapper document that we've called
+personHelper.xml .
+
+
+
+
+
+
+ select
+ PER_ID as ID,
+ PER_FIRST_NAME as FirstName,
+ PER_LAST_NAME as LastName,
+ PER_BIRTH_DATE as BirthDate,
+ PER_WEIGHT_KG as WeightInKilograms,
+ PER_HEIGHT_M as HeightInMeters
+ from PERSON
+ WHERE
+ PER_ID = #value#
+
+
+
+ insert into PERSON
+ (PER_ID, PER_FIRST_NAME, PER_LAST_NAME,
+ PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M)
+ values
+ (#ID#, #FirstName#, #LastName#,
+ #BirthDate#, #WeightInKilograms#, #HeightInMeters#)
+
+
+
+ update PERSON set
+ PER_FIRST_NAME = #FirstName#,
+ PER_LAST_NAME = #LastName#,
+ PER_BIRTH_DATE = #BirthDate#,
+ PER_WEIGHT_KG = #WeightInKilograms#,
+ PER_HEIGHT_M = #HeightInMeters#
+ where PER_ID = #ID#
+
+
+
+ delete from PERSON
+ where PER_ID = #value#
+
+
+
+
+Well, waddya know, if run our tests now, we are favored with a green bar!. It
+all works!
+
+Note:
+Though, of course, things usually do not work perfectly the first time! We
+have to fix this and that, and try, try, again. But SimpleTest makes trying
+again quick and easy. You can changes to the XML mapping documents and rerun
+the tests! No muss, no fuss.
+
+
+Turning back to our Prado page, we can revamp the TDataGrid to allow in-place
+editing and deleting. To add records, we provide a button after the grid that
+inserts a blank person for client to edit. The page code is shown as:
+
+
+ <com:TDataGrid id="personList"
+ DataKeyField="ID"
+ AutoGenerateColumns="False"
+ OnEditCommand="editPerson"
+ OnUpdateCommand="updatePerson"
+ OnCancelCommand="refreshList"
+ OnDeleteCommand="deletePerson">
+ <com:TBoundColumn DataField="FirstName" HeaderText="First Name" />
+ <com:TBoundColumn DataField="LastName" HeaderText="Last Name" />
+ <com:TBoundColumn DataField="HeightInMeters" HeaderText="Height" />
+ <com:TBoundColumn DataField="WeightInKilograms" HeaderText="Weight" />
+ <com:TEditCommandColumn
+ HeaderText="Edit"
+ UpdateText="Save" />
+ <com:TButtonColumn
+ HeaderText="Delete"
+ Text="Delete"
+ CommandName="delete"/>
+ </com:TDataGrid>
+ <com:TButton Text="Add" OnClick="addNewPerson" />
+
+
+
The following sample shows the corresponding methods from page PHP class.
+
+
+ private function sqlmap()
+ {
+ return $this->Application->getModule('SQLMap')->getClient();
+ }
+
+ private function loadData()
+ {
+ $this->personList->DataSource =
+ $this->sqlmap()->queryForList('SelectAll');
+ $this->personList->dataBind();
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ $this->loadData();
+ }
+
+ protected function editPerson($sender,$param)
+ {
+ $this->personList->EditItemIndex=$param->Item->ItemIndex;
+ $this->loadData();
+ }
+
+ protected function deletePerson($sender, $param)
+ {
+ $id = $this->getKey($sender, $param);
+ $this->sqlmap()->update("Delete", $id);
+ $this->loadData();
+ }
+
+ protected function updatePerson($sender, $param)
+ {
+ $person = new Person();
+ $person->FirstName = $this->getText($param, 0);
+ $person->LastName = $this->getText($param, 1);
+ $person->HeightInMeters = $this->getText($param, 2);
+ $person->WeightInKilograms = $this->getText($param, 3);
+ $person->ID = $this->getKey($sender, $param);
+ $this->sqlmap()->update("Update", $person);
+ $this->refreshList($sender, $param);
+ }
+
+ protected function addNewPerson($sender, $param)
+ {
+ $person = new Person;
+ $person->FirstName = "-- New Person --";
+ $this->sqlmap()->insert("Insert", $person);
+ $this->loadData();;
+ }
+
+ protected function refreshList($sender, $param)
+ {
+ $this->personList->EditItemIndex=-1;
+ $this->loadData();
+ }
+
+ private function getText($param, $index)
+ {
+ $item = $param->Item;
+ return $item->Cells[$index]->Controls[0]->Text;
+ }
+
+ private function getKey($sender, $param)
+ {
+ return $sender->DataKeys[$param->Item->DataSourceIndex];
+ }
+
+
+OK, we are CRUD complete! There's more we could do here. In particular, we
+should add validation methods to prevent client from entering alphabetic
+characters where only numbers can live. But, that's a different Prado
+tutorial, and this is an SQLMap DataMapper tutorial.
+
+ class="figure" />
+Figure 4: Person List CRUD
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page b/demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page
new file mode 100644
index 00000000..80a155cb
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page
@@ -0,0 +1,238 @@
+
+Test First!
+
+Let's say that our most important client has a database and one of the tables
+in the database is a list of people. Our client tells us:
+
+"We would like to use a web application to display the people in this table
+and to add, edit, and delete individual records."
+
+Not a complicated story, but it will cover the CRUD most developers want to
+learn first. :) Let's start with the people table that the client mentioned.
+Since we're keeping it simple, we'll say it's a table in an Access database.
+The table definition is shown as:
+
+
+Name Type Size
+PER_ID Long Integer 4
+PER_FIRST_NAME Text 40
+PER_LAST_NAME Text 40
+PER_BIRTH_DATE Date/Time 8
+PER_WEIGHT_KG Double 8
+PER_HEIGHT_M Double 8
+
+
+Tip:
+ This example is bundled with a SQLite database file "Data/test.db"
+ that contains the Person table and some data, ready to use.
+
+
+The first thing our story says is that client would like to display a list of
+people. The following example shows our test for that.
+
+
+<?php
+class PersonTest extends UnitTestCase
+{
+ function testPersonList()
+ {
+ //try it
+ $people = TMapper::instance()->queryForList("SelectAll");
+
+ //test it
+ $this->assertNotNull($people, "Person list is not returned");
+ $this->assertTrue($people->getCount() > 0, "Person list is empty");
+ $person = $people[0];
+ $this->assertNotNull($person, "Person not returned");
+ }
+}
+?>
+
+
+Well, the example sure looks easy enough! We ask a method to "select all", and
+it returns a list of person objects. But, what code do we need to write to
+pass this test?
+
+
+
+Now, to setup the testing framework, suppose you have the SimpleTest
+framework installed. Then we need to create an entry file to run the tests.
+See the SimpleTest documentation for further details on setting up tests.
+
+
+<?php
+require_once('../tests/simpletest/unit_tester.php');
+require_once('../tests/simpletest/reporter.php');
+require_once('../SQLMap/TMapper.php');
+require_once('Models/Person.php');
+
+//supress strict warnings from Adodb.
+error_reporting(E_ALL);
+
+$test = new GroupTest('All tests');
+$test->addTestFile('Tests/PersonTest.php'); $test->run(new HtmlReporter());
+?>
+
+
+To run the tests, point your browser to the "run_test.php " script file
+served from your web server.
+
+Let's see. The test uses a list of person objects. We could start with a blank
+object, just to satisfy the test, and add the display properties later. But
+let's be naughty and skip a step. Our fully-formed person object is shown in
+the following example
+
+
+<?php
+class Person
+{
+ public $ID = -1;
+ public $FirstName;
+ public $LastName;
+ public $WeightInKilograms = 0.0;
+ public $HeightInMeters = 0.0;
+
+ private $_birthDate;
+
+ //setters and getter for BirthDate
+ public function getBirthDate()
+ {
+ return $this->_birthDate;
+ }
+
+ public function setBirthDate($value)
+ {
+ $this->_birthDate = $value;
+ }
+}
+?>
+
+
+OK, that was fun! The $this->assertXXX(...) methods are built into
+UnitTestCase class. So to run the unit test example, we just need the
+TMapper object and queryForList method. Wonderfully, the SQLMap
+DataMapper framework has a TMapper class built into it that will work just
+fine for for us to use in this tutorial, so we don't need to write that
+either.
+
+When the TMapper->instance() method is called, an instance of the SQLMap
+TSqlMapper class is returned that has various methods available such as
+queryForList . In this example, the SQLMap TSqlMapper->queryForList()
+method executes our SQL statement (or stored procedure) and returns the result
+as a list. Each row in the result becomes an entry in the list. Along with
+queryForList() , there are also delete() , insert() ,
+queryForObject() , queryForPagedList() and a few other methods in the
+SQLMap API .
+
+
Looking at unit test example, we see that the queryForList() method
+takes the name of the statement we want to run. OK. Easy enough. But where
+does SQLMap get the "SelectAll" statement? Some systems try to generate SQL
+statements for you, but SQLMap specializes in data mapping, not code
+generation. It's our job (or the job of our database administrator) to craft
+the SQL or provide a stored procedure. We then describe the statement in an
+XML element, like the one shown the following where
+we use XML elements to map a database statement to an application object.
+
+
+
+
+
+ SELECT
+ per_id as ID,
+ per_first_name as FirstName,
+ per_last_name as LastName,
+ per_birth_date as BirthDate,
+ per_weight_kg as WeightInKilograms,
+ per_height_m as HeightInMeters
+ FROM
+ person
+
+
+
+
+
The SQLMap mapping documents can hold several sets of related elements, like
+those shown in the unit test case example. We can also have as many mapping
+documents as we need to help organize our code. Additionally, having multiple
+mapping documents is handy when several developers are working on the project
+at once.
+
+So, the framework gets the SQL code for the query from the mapping, and plugs
+it into a prepared statement. But, how does SQLMap know where to find the
+table's datasource?
+
+Surprise! More XML! You can define a configuration file for each datasource
+your application uses. The following code shows a configuration file named "sqlmap.config " for
+our SQLite database.
+
+
+
+
+
+
+
+
+
+
+
+
+
+The <provider> specifies the database provider class, in this case
+TAdodbProvider using the Adodb library. The <datasource> tag
+specifies the database connection details. In this case, for an SQLite
+database, we just need the driver name, and the host that points to the actual
+SQLite database file.
+
+The last part of the configuration file ("sqlMaps") is where we list our
+mapping documents, like the one shown back in the previous code sample. We can
+list as many documents as we need here, and they will all be read when the
+configuration is parsed.
+
+OK, so how does the configuration get parsed?
+
+Look back at the unit test case example. The heart of the code is the call to the
+"TMapper " object (under the remark "try it"). The TMapper object
+is a singleton that handles the instantiation and configuration of an SQLMap
+TSqlMapper object, which provides a facade to the SQLMap DataMapper
+framework API.
+
+The first time that the TMapper is called, it reads in the
+sqlmap.config file and associated mapping documents to create an instance
+of the TSqlMapper class. On subsequent calls, it reuses the
+TSqlMapper object so that the configuration is not re-read.
+
+The framework comes bundled with a default TMapper class for you to use
+immediately to get access to the SQLMap client TSqlMapper object. If you want to use a
+different name other than sqlmap.config at the default location for the
+configuration file, or need to use more than one database and have one
+TSqlMapper per database, you can also write your own class to mimic the role of
+the Mapper class view by copying and modifying the standard version.
+
+Tip:
+ You can also call TMapper::configure('/path/to/your/sqlmap.config')
+ to configure the TMapper for a specific configuration file.
+
+
+If we put this all together into a solution, we can "green bar" our test. At
+this point you should have the following files.
+
+Data/person.xml % Mapping file.
+Data/test.db % SQLite database file.
+
+Models/Person.php % Person class file.
+
+Tests/PersonTest.php % Unit test case for Person mapping.
+
+run_tests.php % Unit test entry point.
+sqlmap.config % SQLMap configuration file.
+
+
+Run the tests by pointing your browser URL to the "run_tests.php " server
+file.
+
+ class="figure" />
+Figure 2: Green Bar!
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page b/demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page
new file mode 100644
index 00000000..706b5220
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page
@@ -0,0 +1,116 @@
+
+
+Playtest second!
+Now that we have a passing test, we want to display some results as web pages.
+The following examples utilize the Prado framework to display and manipulate
+the database through SQLMap. Since SQLMap framework and Prado framework solve
+different problems, they are both fairly independent, they can be used
+together or separately.
+
+SQLMap and Prado
+To setup Prado, we need to create the follow files and directory structure
+under our example/WebView directory.
+
+assets/ % application public assets
+
+protected/pages/Home.page % default page
+protected/pages/Home.php % default page class
+protected/runtime/ % run time data
+
+protected/application.xml % application configuration
+
+index.php % application entry point
+
+
+The application.xml and assets directory are not necessary but we
+will make use of them later. The application.xml is used to define some
+directory aliases and override the data source definitions in the
+sqlmap.config . This is because SQLite database files are defined
+relatively, otherwise we don't need to override the data source definitions.
+The example application.xml is shown below, defining path aliases and override SQLite database
+location.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+The entry point to a Prado application in this example is index.php
+and generally contains the following code.
+
+
+<?php
+error_reporting(E_ALL);
+require_once('/path/to/prado/framework/prado.php');
+$application=new TApplication;
+$application->run();
+?>
+
+
+Now we are ready to setup a page to display our list of people.
+The following sample shows the Prado code for our display page. The key
+piece is the TDataGrid . We save the file as Home.page .
+
+
+
+
+
+ Person
+
+
+<com:TForm>
+ Person List
+ <com:TDataGrid id="personList">
+ <com:TBoundColumn DataField="BirthDate"
+ HeaderText="Birth Date"/>
+ </com:TDataGrid>
+</com:TForm>
+
+
+
+
+Of course, we still need to populate that TDataGrid. The following code
+shows the PHP for Home.php . The operative method is loadData() .
+The rest is supporting code.
+
+
+<?php
+Prado::using('Example.Models.Person');
+class Home extends TPage
+{
+ private function loadData()
+ {
+ $sqlmap = $this->Application->getModule('SQLMap')->getClient();
+ $this->personList->DataSource = $sqlmap->queryForList('SelectAll');
+ $this->personList->dataBind();
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ $this->loadData();
+ }
+}
+?>
+
+
+If we run this now, we'll get a list like the one shown the figure below.
+ class="figure" />
+Figure 3: A quick-and-dirty Person List
+
+
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/example1.png b/demos/sqlmap/protected/pages/Manual/Tutorial/example1.png
new file mode 100644
index 00000000..b5241de6
Binary files /dev/null and b/demos/sqlmap/protected/pages/Manual/Tutorial/example1.png differ
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png b/demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png
new file mode 100644
index 00000000..845b9581
Binary files /dev/null and b/demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png differ
diff --git a/demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png b/demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png
new file mode 100644
index 00000000..dcafc33d
Binary files /dev/null and b/demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png differ
diff --git a/demos/sqlmap/protected/pages/Tutorial/TestAgain.page b/demos/sqlmap/protected/pages/Tutorial/TestAgain.page
deleted file mode 100644
index 4adac73b..00000000
--- a/demos/sqlmap/protected/pages/Tutorial/TestAgain.page
+++ /dev/null
@@ -1,214 +0,0 @@
-
-Test, test, again ...
-Of course, tweaking the Person List display is not going to be the end of it.
-Clients always want more, and now ours wants to edit, add, or delete records.
-Let's write some tests for these new tasks, as shown in the following.
-
-
-function testPersonUpdate()
-{
- $expect = "wei";
- $edited = "Nah";
-
- //get it;
- $person = TMapper::instance()->queryForObject("Select", 1);
-
- //test it
- $this->assertNotNull($person);
- $this->assertEqual($expect, $person->FirstName);
-
- //change it
- $person->FirstName = $edited;
- TMapper::instance()->update("Update", $person);
-
- //get it again
- $person = TMapper::instance()->queryForObject("Select", 1);
-
- //test it
- $this->assertEqual($edited, $person->FirstName);
-
- //change it back
- $person->FirstName = $expect;
- TMapper::instance()->update("Update", $person);
-}
-
-function testPersonDelete()
-{
- //insert it
- $person = new Person;
- $person->ID = -1;
- TMapper::instance()->insert("Insert", $person);
-
- //delte it
- $count = TMapper::instance()->delete("Delete", -1);
- $this->assertEqual(1, $count);
-}
-
-
-Not the best tests ever written, but for now, they will do :)
-
-To make the new tests work, we'll need some new mapping statements.
-The following sample shows the complete mapper document that we've called
-personHelper.xml .
-
-
-
-
-
-
- select
- PER_ID as ID,
- PER_FIRST_NAME as FirstName,
- PER_LAST_NAME as LastName,
- PER_BIRTH_DATE as BirthDate,
- PER_WEIGHT_KG as WeightInKilograms,
- PER_HEIGHT_M as HeightInMeters
- from PERSON
- WHERE
- PER_ID = #value#
-
-
-
- insert into PERSON
- (PER_ID, PER_FIRST_NAME, PER_LAST_NAME,
- PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M)
- values
- (#ID#, #FirstName#, #LastName#,
- #BirthDate#, #WeightInKilograms#, #HeightInMeters#)
-
-
-
- update PERSON set
- PER_FIRST_NAME = #FirstName#,
- PER_LAST_NAME = #LastName#,
- PER_BIRTH_DATE = #BirthDate#,
- PER_WEIGHT_KG = #WeightInKilograms#,
- PER_HEIGHT_M = #HeightInMeters#
- where PER_ID = #ID#
-
-
-
- delete from PERSON
- where PER_ID = #value#
-
-
-
-
-Well, waddya know, if run our tests now, we are favored with a green bar!. It
-all works!
-
-Note:
-Though, of course, things usually do not work perfectly the first time! We
-have to fix this and that, and try, try, again. But SimpleTest makes trying
-again quick and easy. You can changes to the XML mapping documents and rerun
-the tests! No muss, no fuss.
-
-
-Turning back to our Prado page, we can revamp the TDataGrid to allow in-place
-editing and deleting. To add records, we provide a button after the grid that
-inserts a blank person for client to edit. The page code is shown as:
-
-
- <com:TDataGrid id="personList"
- DataKeyField="ID"
- AutoGenerateColumns="False"
- OnEditCommand="editPerson"
- OnUpdateCommand="updatePerson"
- OnCancelCommand="refreshList"
- OnDeleteCommand="deletePerson">
- <com:TBoundColumn DataField="FirstName" HeaderText="First Name" />
- <com:TBoundColumn DataField="LastName" HeaderText="Last Name" />
- <com:TBoundColumn DataField="HeightInMeters" HeaderText="Height" />
- <com:TBoundColumn DataField="WeightInKilograms" HeaderText="Weight" />
- <com:TEditCommandColumn
- HeaderText="Edit"
- UpdateText="Save" />
- <com:TButtonColumn
- HeaderText="Delete"
- Text="Delete"
- CommandName="delete"/>
- </com:TDataGrid>
- <com:TButton Text="Add" OnClick="addNewPerson" />
-
-
-
The following sample shows the corresponding methods from page PHP class.
-
-
- private function sqlmap()
- {
- return $this->Application->getModule('SQLMap')->getClient();
- }
-
- private function loadData()
- {
- $this->personList->DataSource =
- $this->sqlmap()->queryForList('SelectAll');
- $this->personList->dataBind();
- }
-
- public function onLoad($param)
- {
- if(!$this->IsPostBack)
- $this->loadData();
- }
-
- protected function editPerson($sender,$param)
- {
- $this->personList->EditItemIndex=$param->Item->ItemIndex;
- $this->loadData();
- }
-
- protected function deletePerson($sender, $param)
- {
- $id = $this->getKey($sender, $param);
- $this->sqlmap()->update("Delete", $id);
- $this->loadData();
- }
-
- protected function updatePerson($sender, $param)
- {
- $person = new Person();
- $person->FirstName = $this->getText($param, 0);
- $person->LastName = $this->getText($param, 1);
- $person->HeightInMeters = $this->getText($param, 2);
- $person->WeightInKilograms = $this->getText($param, 3);
- $person->ID = $this->getKey($sender, $param);
- $this->sqlmap()->update("Update", $person);
- $this->refreshList($sender, $param);
- }
-
- protected function addNewPerson($sender, $param)
- {
- $person = new Person;
- $person->FirstName = "-- New Person --";
- $this->sqlmap()->insert("Insert", $person);
- $this->loadData();;
- }
-
- protected function refreshList($sender, $param)
- {
- $this->personList->EditItemIndex=-1;
- $this->loadData();
- }
-
- private function getText($param, $index)
- {
- $item = $param->Item;
- return $item->Cells[$index]->Controls[0]->Text;
- }
-
- private function getKey($sender, $param)
- {
- return $sender->DataKeys[$param->Item->DataSourceIndex];
- }
-
-
-OK, we are CRUD complete! There's more we could do here. In particular, we
-should add validation methods to prevent client from entering alphabetic
-characters where only numbers can live. But, that's a different Prado
-tutorial, and this is an SQLMap DataMapper tutorial.
-
- class="figure" />
-Figure 4: Person List CRUD
-
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Tutorial/TestFirst.page b/demos/sqlmap/protected/pages/Tutorial/TestFirst.page
deleted file mode 100644
index 80a155cb..00000000
--- a/demos/sqlmap/protected/pages/Tutorial/TestFirst.page
+++ /dev/null
@@ -1,238 +0,0 @@
-
-Test First!
-
-Let's say that our most important client has a database and one of the tables
-in the database is a list of people. Our client tells us:
-
-"We would like to use a web application to display the people in this table
-and to add, edit, and delete individual records."
-
-Not a complicated story, but it will cover the CRUD most developers want to
-learn first. :) Let's start with the people table that the client mentioned.
-Since we're keeping it simple, we'll say it's a table in an Access database.
-The table definition is shown as:
-
-
-Name Type Size
-PER_ID Long Integer 4
-PER_FIRST_NAME Text 40
-PER_LAST_NAME Text 40
-PER_BIRTH_DATE Date/Time 8
-PER_WEIGHT_KG Double 8
-PER_HEIGHT_M Double 8
-
-
-Tip:
- This example is bundled with a SQLite database file "Data/test.db"
- that contains the Person table and some data, ready to use.
-
-
-The first thing our story says is that client would like to display a list of
-people. The following example shows our test for that.
-
-
-<?php
-class PersonTest extends UnitTestCase
-{
- function testPersonList()
- {
- //try it
- $people = TMapper::instance()->queryForList("SelectAll");
-
- //test it
- $this->assertNotNull($people, "Person list is not returned");
- $this->assertTrue($people->getCount() > 0, "Person list is empty");
- $person = $people[0];
- $this->assertNotNull($person, "Person not returned");
- }
-}
-?>
-
-
-Well, the example sure looks easy enough! We ask a method to "select all", and
-it returns a list of person objects. But, what code do we need to write to
-pass this test?
-
-
-
-Now, to setup the testing framework, suppose you have the SimpleTest
-framework installed. Then we need to create an entry file to run the tests.
-See the SimpleTest documentation for further details on setting up tests.
-
-
-<?php
-require_once('../tests/simpletest/unit_tester.php');
-require_once('../tests/simpletest/reporter.php');
-require_once('../SQLMap/TMapper.php');
-require_once('Models/Person.php');
-
-//supress strict warnings from Adodb.
-error_reporting(E_ALL);
-
-$test = new GroupTest('All tests');
-$test->addTestFile('Tests/PersonTest.php'); $test->run(new HtmlReporter());
-?>
-
-
-To run the tests, point your browser to the "run_test.php " script file
-served from your web server.
-
-Let's see. The test uses a list of person objects. We could start with a blank
-object, just to satisfy the test, and add the display properties later. But
-let's be naughty and skip a step. Our fully-formed person object is shown in
-the following example
-
-
-<?php
-class Person
-{
- public $ID = -1;
- public $FirstName;
- public $LastName;
- public $WeightInKilograms = 0.0;
- public $HeightInMeters = 0.0;
-
- private $_birthDate;
-
- //setters and getter for BirthDate
- public function getBirthDate()
- {
- return $this->_birthDate;
- }
-
- public function setBirthDate($value)
- {
- $this->_birthDate = $value;
- }
-}
-?>
-
-
-OK, that was fun! The $this->assertXXX(...) methods are built into
-UnitTestCase class. So to run the unit test example, we just need the
-TMapper object and queryForList method. Wonderfully, the SQLMap
-DataMapper framework has a TMapper class built into it that will work just
-fine for for us to use in this tutorial, so we don't need to write that
-either.
-
-When the TMapper->instance() method is called, an instance of the SQLMap
-TSqlMapper class is returned that has various methods available such as
-queryForList . In this example, the SQLMap TSqlMapper->queryForList()
-method executes our SQL statement (or stored procedure) and returns the result
-as a list. Each row in the result becomes an entry in the list. Along with
-queryForList() , there are also delete() , insert() ,
-queryForObject() , queryForPagedList() and a few other methods in the
-SQLMap API .
-
-
Looking at unit test example, we see that the queryForList() method
-takes the name of the statement we want to run. OK. Easy enough. But where
-does SQLMap get the "SelectAll" statement? Some systems try to generate SQL
-statements for you, but SQLMap specializes in data mapping, not code
-generation. It's our job (or the job of our database administrator) to craft
-the SQL or provide a stored procedure. We then describe the statement in an
-XML element, like the one shown the following where
-we use XML elements to map a database statement to an application object.
-
-
-
-
-
- SELECT
- per_id as ID,
- per_first_name as FirstName,
- per_last_name as LastName,
- per_birth_date as BirthDate,
- per_weight_kg as WeightInKilograms,
- per_height_m as HeightInMeters
- FROM
- person
-
-
-
-
-
The SQLMap mapping documents can hold several sets of related elements, like
-those shown in the unit test case example. We can also have as many mapping
-documents as we need to help organize our code. Additionally, having multiple
-mapping documents is handy when several developers are working on the project
-at once.
-
-So, the framework gets the SQL code for the query from the mapping, and plugs
-it into a prepared statement. But, how does SQLMap know where to find the
-table's datasource?
-
-Surprise! More XML! You can define a configuration file for each datasource
-your application uses. The following code shows a configuration file named "sqlmap.config " for
-our SQLite database.
-
-
-
-
-
-
-
-
-
-
-
-
-
-The <provider> specifies the database provider class, in this case
-TAdodbProvider using the Adodb library. The <datasource> tag
-specifies the database connection details. In this case, for an SQLite
-database, we just need the driver name, and the host that points to the actual
-SQLite database file.
-
-The last part of the configuration file ("sqlMaps") is where we list our
-mapping documents, like the one shown back in the previous code sample. We can
-list as many documents as we need here, and they will all be read when the
-configuration is parsed.
-
-OK, so how does the configuration get parsed?
-
-Look back at the unit test case example. The heart of the code is the call to the
-"TMapper " object (under the remark "try it"). The TMapper object
-is a singleton that handles the instantiation and configuration of an SQLMap
-TSqlMapper object, which provides a facade to the SQLMap DataMapper
-framework API.
-
-The first time that the TMapper is called, it reads in the
-sqlmap.config file and associated mapping documents to create an instance
-of the TSqlMapper class. On subsequent calls, it reuses the
-TSqlMapper object so that the configuration is not re-read.
-
-The framework comes bundled with a default TMapper class for you to use
-immediately to get access to the SQLMap client TSqlMapper object. If you want to use a
-different name other than sqlmap.config at the default location for the
-configuration file, or need to use more than one database and have one
-TSqlMapper per database, you can also write your own class to mimic the role of
-the Mapper class view by copying and modifying the standard version.
-
-Tip:
- You can also call TMapper::configure('/path/to/your/sqlmap.config')
- to configure the TMapper for a specific configuration file.
-
-
-If we put this all together into a solution, we can "green bar" our test. At
-this point you should have the following files.
-
-Data/person.xml % Mapping file.
-Data/test.db % SQLite database file.
-
-Models/Person.php % Person class file.
-
-Tests/PersonTest.php % Unit test case for Person mapping.
-
-run_tests.php % Unit test entry point.
-sqlmap.config % SQLMap configuration file.
-
-
-Run the tests by pointing your browser URL to the "run_tests.php " server
-file.
-
- class="figure" />
-Figure 2: Green Bar!
-
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Tutorial/TestSecond.page b/demos/sqlmap/protected/pages/Tutorial/TestSecond.page
deleted file mode 100644
index 706b5220..00000000
--- a/demos/sqlmap/protected/pages/Tutorial/TestSecond.page
+++ /dev/null
@@ -1,116 +0,0 @@
-
-
-Playtest second!
-Now that we have a passing test, we want to display some results as web pages.
-The following examples utilize the Prado framework to display and manipulate
-the database through SQLMap. Since SQLMap framework and Prado framework solve
-different problems, they are both fairly independent, they can be used
-together or separately.
-
-SQLMap and Prado
-To setup Prado, we need to create the follow files and directory structure
-under our example/WebView directory.
-
-assets/ % application public assets
-
-protected/pages/Home.page % default page
-protected/pages/Home.php % default page class
-protected/runtime/ % run time data
-
-protected/application.xml % application configuration
-
-index.php % application entry point
-
-
-The application.xml and assets directory are not necessary but we
-will make use of them later. The application.xml is used to define some
-directory aliases and override the data source definitions in the
-sqlmap.config . This is because SQLite database files are defined
-relatively, otherwise we don't need to override the data source definitions.
-The example application.xml is shown below, defining path aliases and override SQLite database
-location.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-The entry point to a Prado application in this example is index.php
-and generally contains the following code.
-
-
-<?php
-error_reporting(E_ALL);
-require_once('/path/to/prado/framework/prado.php');
-$application=new TApplication;
-$application->run();
-?>
-
-
-Now we are ready to setup a page to display our list of people.
-The following sample shows the Prado code for our display page. The key
-piece is the TDataGrid . We save the file as Home.page .
-
-
-
-
-
- Person
-
-
-<com:TForm>
- Person List
- <com:TDataGrid id="personList">
- <com:TBoundColumn DataField="BirthDate"
- HeaderText="Birth Date"/>
- </com:TDataGrid>
-</com:TForm>
-
-
-
-
-Of course, we still need to populate that TDataGrid. The following code
-shows the PHP for Home.php . The operative method is loadData() .
-The rest is supporting code.
-
-
-<?php
-Prado::using('Example.Models.Person');
-class Home extends TPage
-{
- private function loadData()
- {
- $sqlmap = $this->Application->getModule('SQLMap')->getClient();
- $this->personList->DataSource = $sqlmap->queryForList('SelectAll');
- $this->personList->dataBind();
- }
-
- public function onLoad($param)
- {
- if(!$this->IsPostBack)
- $this->loadData();
- }
-}
-?>
-
-
-If we run this now, we'll get a list like the one shown the figure below.
- class="figure" />
-Figure 3: A quick-and-dirty Person List
-
-
\ No newline at end of file
diff --git a/demos/sqlmap/protected/pages/Tutorial/example1.png b/demos/sqlmap/protected/pages/Tutorial/example1.png
deleted file mode 100644
index b5241de6..00000000
Binary files a/demos/sqlmap/protected/pages/Tutorial/example1.png and /dev/null differ
diff --git a/demos/sqlmap/protected/pages/Tutorial/grid1.png b/demos/sqlmap/protected/pages/Tutorial/grid1.png
deleted file mode 100644
index 845b9581..00000000
Binary files a/demos/sqlmap/protected/pages/Tutorial/grid1.png and /dev/null differ
diff --git a/demos/sqlmap/protected/pages/Tutorial/grid2.png b/demos/sqlmap/protected/pages/Tutorial/grid2.png
deleted file mode 100644
index dcafc33d..00000000
Binary files a/demos/sqlmap/protected/pages/Tutorial/grid2.png and /dev/null differ
diff --git a/demos/sqlmap/protected/pages/config.xml b/demos/sqlmap/protected/pages/config.xml
deleted file mode 100644
index e0850c2c..00000000
--- a/demos/sqlmap/protected/pages/config.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/BaseDao.php b/demos/time-tracker/protected/APP_CODE/BaseDao.php
index f9146b59..63b91def 100644
--- a/demos/time-tracker/protected/APP_CODE/BaseDao.php
+++ b/demos/time-tracker/protected/APP_CODE/BaseDao.php
@@ -1,14 +1,41 @@
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+/**
+ * Base DAO class.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
class BaseDao
{
+ /**
+ * @var TSqlMapper sqlmap client.
+ */
private $_connection;
+ /**
+ * @param TSqlMapper sqlmap client.
+ */
public function setConnection($connection)
{
$this->_connection = $connection;
}
+ /**
+ * @return TSqlMapper sqlmap client.
+ */
protected function getConnection()
{
return $this->_connection;
diff --git a/demos/time-tracker/protected/APP_CODE/DaoManager.php b/demos/time-tracker/protected/APP_CODE/DaoManager.php
new file mode 100644
index 00000000..b8ac55af
--- /dev/null
+++ b/demos/time-tracker/protected/APP_CODE/DaoManager.php
@@ -0,0 +1,126 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * DaoManager class.
+ *
+ * A Registry for Dao and an implementation of that type.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class DaoManager extends TModule
+{
+ /**
+ * @var TSqlMapper sqlmap client
+ */
+ private $_connection;
+ /**
+ * @var boolean if the module has been initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var array registered list of dao
+ */
+ private $_dao=array();
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * It loads dao information from the module configuration.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ if($this->_connection === null)
+ throw new TimeTrackerException('daomanager_connection_required');
+ $app = $this->getApplication();
+ if(is_string($this->_connection))
+ {
+ if(($conn=$app->getModule($this->_connection)->getClient())===null)
+ throw new TimeTrackerException('daomanager_undefined_connection',$this->_connection);
+ if(!($conn instanceof TSqlMapper))
+ throw new TimeTrackerException('daomanager_invalid_connection', $this->_connection);
+ $this->_connection = $conn;
+ }
+ $this->includeDaoImplementation($config->getElementsByTagName('dao'));
+ $this->_initialized = true;
+ }
+
+ /**
+ * Register the dao type and implementation class names.
+ * @param array list of TXmlDocument nodes.
+ */
+ protected function includeDaoImplementation($nodes)
+ {
+ foreach($nodes as $node)
+ {
+ $id = $node->getAttribute('id');
+ $class = $node->getAttribute('class');
+ $this->_dao[$id] = array('class' => $class);
+ }
+ }
+
+ /**
+ * @return array list of registered Daos
+ */
+ public function getDaos()
+ {
+ return $this->_dao;
+ }
+
+ /**
+ * Returns an implementation of a Dao type, implements the Registery
+ * pattern. Multiple calls returns the same Dao instance.
+ * @param string Dao type to find.
+ * @return object instance of the Dao implementation.
+ */
+ public function getDao($class)
+ {
+ if(isset($this->_dao[$class]))
+ {
+ if(!isset($this->_dao[$class]['instance']))
+ {
+ $dao = Prado::createComponent($this->_dao[$class]['class']);
+ $dao->setConnection($this->getConnection());
+ $this->_dao[$class]['instance'] = $dao;
+ }
+ return $this->_dao[$class]['instance'];
+ }
+ else
+ throw TimeTrackerException('daomanager_undefined_dao', $class);
+ }
+
+ /**
+ * @return TSqlMapper sqlmap client instance
+ */
+ public function getConnection()
+ {
+ return $this->_connection;
+ }
+
+ /**
+ * Sets the connection for all Daos registered.
+ * @param string|TSqlMapper sqlmap client module id or TSqlMapper instance.
+ */
+ public function setConnection($client)
+ {
+ if($this->_initialized)
+ throw new TimeTrackerException('daomanager_unchangeable');
+ if(!is_string($client) && !($client instanceof TSqlMapper))
+ throw new TConfigurationException('daomanager_invalid_connection',$client);
+ $this->_connection = $client;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/Project.php b/demos/time-tracker/protected/APP_CODE/Project.php
index ad9f7d19..660fad04 100644
--- a/demos/time-tracker/protected/APP_CODE/Project.php
+++ b/demos/time-tracker/protected/APP_CODE/Project.php
@@ -1,5 +1,23 @@
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+/**
+ * Time Tracker Project class.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
class Project
{
public $ActualDuration = 0;
diff --git a/demos/time-tracker/protected/APP_CODE/ProjectDao.php b/demos/time-tracker/protected/APP_CODE/ProjectDao.php
index 25a2845d..81902e0c 100644
--- a/demos/time-tracker/protected/APP_CODE/ProjectDao.php
+++ b/demos/time-tracker/protected/APP_CODE/ProjectDao.php
@@ -1,10 +1,26 @@
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
-Prado::using('Application.APP_CODE.BaseDao');
-
+/**
+ * Project DAO class.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
class ProjectDao extends BaseDao
{
- public function createNewProject($project)
+/* public function createNewProject($project)
{
$sqlmap = $this->getConnection();
$creator = $sqlmap->queryForObject('GetUserByName', $project->CreatorUserName);
@@ -71,6 +87,7 @@ class ProjectDao extends BaseDao
return $sqlmap->insert('AddUserToProject', $param);
}
}
+*/
}
?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/TimeTrackerException.php b/demos/time-tracker/protected/APP_CODE/TimeTrackerException.php
index d715eefa..64b11405 100644
--- a/demos/time-tracker/protected/APP_CODE/TimeTrackerException.php
+++ b/demos/time-tracker/protected/APP_CODE/TimeTrackerException.php
@@ -1,5 +1,24 @@
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+/**
+ * Generic time tracker application exception. Exception messages are saved in
+ * "exceptions.txt"
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
class TimeTrackerException extends TException
{
/**
diff --git a/demos/time-tracker/protected/APP_CODE/TimeTrackerUser.php b/demos/time-tracker/protected/APP_CODE/TimeTrackerUser.php
index 4b6987bd..99ac1209 100644
--- a/demos/time-tracker/protected/APP_CODE/TimeTrackerUser.php
+++ b/demos/time-tracker/protected/APP_CODE/TimeTrackerUser.php
@@ -1,31 +1,48 @@
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+/**
+ * Import TUser and TUserManager
+ */
Prado::using('System.Security.TUser');
Prado::using('System.Security.TUserManager');
+/**
+ * User class for Time Tracker application.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
class TimeTrackerUser extends TUser
{
- private $_ID;
+ private $_emailAddress;
- public function __construct()
+ /**
+ * @param string user email address
+ */
+ public function setEmailAddress($value)
{
- parent::__construct(new TUserManager());
+ $this->_emailAddress = $value;
}
-
- public function getID(){ return $this->_ID; }
- public function setID($value)
- {
- if(is_null($this->_ID))
- $this->_ID = $value;
- else
- throw new TimeTrackerUserException(
- 'timetracker_user_readonly_id');
- }
-}
-
-class TimeTrackerUserException extends TimeTrackerException
-{
+ /**
+ * @return string user email address
+ */
+ public function getEmailAddress()
+ {
+ return $this->_emailAddress;
+ }
}
?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/TimeTrackerUserTypeHandler.php b/demos/time-tracker/protected/APP_CODE/TimeTrackerUserTypeHandler.php
new file mode 100644
index 00000000..07c46acc
--- /dev/null
+++ b/demos/time-tracker/protected/APP_CODE/TimeTrackerUserTypeHandler.php
@@ -0,0 +1,54 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * SQLMap type handler for TimeTrackerUser.
+ * The TimeTrackerUser requires an instance of IUserManager in constructor.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class TimeTrackerUserTypeHandler implements ITypeHandlerCallback
+{
+ /**
+ * Not implemented.
+ */
+ public function getParameter($object)
+ {
+ throw new TimeTrackerException('Not implemented');
+ }
+
+ /**
+ * Not implemented.
+ */
+ public function getResult($string)
+ {
+ throw new TimeTrackerException('Not implemented');
+ }
+
+ /**
+ * Creates a new instance of TimeTrackerUser
+ * @param array result data
+ * @return TimeTrackerUser new user instance
+ */
+ public function createNewInstance($row=null)
+ {
+ $manager = Prado::getApplication()->getModule('users');
+ if(is_null($manager))
+ $manager = new UserManager();
+ return new TimeTrackerUser($manager);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/UserDao.php b/demos/time-tracker/protected/APP_CODE/UserDao.php
new file mode 100644
index 00000000..4dc39b2b
--- /dev/null
+++ b/demos/time-tracker/protected/APP_CODE/UserDao.php
@@ -0,0 +1,155 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * UserDao class list, create, find and delete users.
+ * In addition, it can validate username and password, and update
+ * the user roles. Furthermore, a unique new token can be generated,
+ * this token can be used to perform persistent cookie login.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class UserDao extends BaseDao
+{
+ /**
+ * @param string username
+ * @return TimeTrackerUser find by user name, null if not found or disabled.
+ */
+ public function getUserByName($username)
+ {
+ $sqlmap = $this->getConnection();
+ return $sqlmap->queryForObject('GetUserByName', $username);
+ }
+
+ /**
+ * @return array list of all enabled users.
+ */
+ public function getAllUsers()
+ {
+ $sqlmap = $this->getConnection();
+ return $sqlmap->queryForList('GetAllUsers');
+ }
+
+ /**
+ * @param TimeTrackerUser new user details.
+ * @param string new user password.
+ */
+ public function addNewUser($user, $password)
+ {
+ $sqlmap = $this->getConnection();
+ $param['user'] = $user;
+ $param['password'] = md5($password);
+ $sqlmap->insert('AddNewUser', $param);
+ if(count($user->getRoles()) > 0)
+ $this->updateUserRoles($user);
+ }
+
+ /**
+ * @param string username to delete
+ */
+ public function deleteUserByName($username)
+ {
+ $sqlmap = $this->getConnection();
+ $sqlmap->delete('DeleteUserByName', $username);
+ }
+
+ /**
+ * Updates the user profile details, including user roles.
+ * @param TimeTrackerUser updated user details.
+ * @param string new user password, null to avoid updating password.
+ */
+ public function updateUser($user,$password=null)
+ {
+ $sqlmap = $this->getConnection();
+ if($password !== null)
+ {
+ $param['user'] = $user;
+ $param['password'] = md5($password);
+ $sqlmap->update('UpdateUserDetailsAndPassword', $param);
+ }
+ else
+ {
+ $sqlmap->update('UpdateUserDetails', $user);
+ }
+ $this->updateUserRoles($user);
+ }
+
+ /**
+ * @param string username to be validated
+ * @param string matching password
+ * @return boolean true if the username and password matches.
+ */
+ public function validateUser($username, $password)
+ {
+ $sqlmap = $this->getConnection();
+ $param['username'] = $username;
+ $param['password'] = md5($password);
+ return $sqlmap->queryForObject('ValidateUser', $param);
+ }
+
+ /**
+ * @param string unique persistent session token
+ * @return TimeTrackerUser user details if valid token, null otherwise.
+ */
+ public function validateSignon($token)
+ {
+ $sqlmap = $this->getConnection();
+ $sqlmap->update('UpdateSignon', $token);
+ return $sqlmap->queryForObject('ValidateAutoSignon', $token);
+ }
+
+ /**
+ * @param TimeTrackerUser user details to generate the token
+ * @return string unique persistent login token.
+ */
+ public function createSignonToken($user)
+ {
+ $sqlmap = $this->getConnection();
+ $param['username'] = $user->getName();
+ $param['token'] = md5(microtime().$param['username']);
+ $sqlmap->insert('RegisterAutoSignon', $param);
+ return $param['token'];
+ }
+
+ /**
+ * @param TimeTrackerUser deletes all signon token for given user, null to delete all
+ * tokens.
+ */
+ public function clearSignonTokens($user=null)
+ {
+ $sqlmap = $this->getConnection();
+ if($user !== null)
+ $sqlmap->delete('DeleteAutoSignon', $user->getName());
+ else
+ $sqlmap->delete('DeleteAllSignon');
+ }
+
+ /**
+ * @param TimeTrackerUser user details for updating the assigned roles.
+ */
+ public function updateUserRoles($user)
+ {
+ $sqlmap = $this->getConnection();
+ $sqlmap->delete('DeleteUserRoles', $user);
+ foreach($user->getRoles() as $role)
+ {
+ $param['username'] = $user->getName();
+ $param['role'] = $role;
+ $sqlmap->update('AddUserRole', $param);
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/UserManager.php b/demos/time-tracker/protected/APP_CODE/UserManager.php
new file mode 100644
index 00000000..1327dc3c
--- /dev/null
+++ b/demos/time-tracker/protected/APP_CODE/UserManager.php
@@ -0,0 +1,68 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * User manager module class for time tracker application.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class UserManager extends TModule implements IUserManager
+{
+ /**
+ * @return string name for a guest user.
+ */
+ public function getGuestName()
+ {
+ return 'Guest';
+ }
+
+ /**
+ * Returns a user instance given the user name.
+ * @param string user name, null if it is a guest.
+ * @return TUser the user instance, null if the specified username is not in the user database.
+ */
+ public function getUser($username=null)
+ {
+ if($username===null)
+ {
+ $user=new TUser($this);
+ $user->setIsGuest(true);
+ return $user;
+ }
+ else
+ {
+ $daos = $this->getApplication()->getModule('daos');
+ $userDao = $daos->getDao('UserDao');
+ $user = $userDao->getUserByName($username);
+ $user->setIsGuest(false);
+ return $user;
+ }
+ }
+
+ /**
+ * Validates if the username and password are correct.
+ * @param string user name
+ * @param string password
+ * @return boolean true if validation is successful, false otherwise.
+ */
+ public function validateUser($username,$password)
+ {
+ $daos = $this->getApplication()->getModule('daos');
+ $userDao = $daos->getDao('UserDao');
+ return $userDao->validateUser($username, $password);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/APP_CODE/exceptions.txt b/demos/time-tracker/protected/APP_CODE/exceptions.txt
index e948f4d0..6568cc72 100644
--- a/demos/time-tracker/protected/APP_CODE/exceptions.txt
+++ b/demos/time-tracker/protected/APP_CODE/exceptions.txt
@@ -1,3 +1,7 @@
timetracker_user_readonly_id = Time tracker user ID is read-only.
invalid_creator_and_manager = Unable to find time tracker usernames '{1}' and '{2}' for project '{0}'.
-project_exists = Project '{0}' already exists.
\ No newline at end of file
+project_exists = Project '{0}' already exists.
+daomanager_connection_required = An TSqlMapper connection is required by Dao Manager.
+daomanager_undefined_connection = Connection '{0}' for Dao Manager is undefined.
+daomanager_invalid_connection = Connection '{0}' does not appear to ba a TSqlMapper in Dao Manager.
+daomanager_undefined_dao = Dao class '{0}' is not registered.
\ No newline at end of file
diff --git a/demos/time-tracker/protected/App_Data/time_tracker.db b/demos/time-tracker/protected/App_Data/time_tracker.db
new file mode 100644
index 00000000..03fe9156
Binary files /dev/null and b/demos/time-tracker/protected/App_Data/time_tracker.db differ
diff --git a/demos/time-tracker/protected/data/time_tracker.db b/demos/time-tracker/protected/data/time_tracker.db
deleted file mode 100644
index 03fe9156..00000000
Binary files a/demos/time-tracker/protected/data/time_tracker.db and /dev/null differ
diff --git a/demos/time-tracker/protected/pages/Docs/TopicList.tpl b/demos/time-tracker/protected/pages/Docs/TopicList.tpl
index 5fa2adb5..53243578 100644
--- a/demos/time-tracker/protected/pages/Docs/TopicList.tpl
+++ b/demos/time-tracker/protected/pages/Docs/TopicList.tpl
@@ -14,7 +14,7 @@
Testing Business Code
- Create Business Code
+ Database Design
Using SQLMap Data Mapper
User Class and Exceptions
More Tests
diff --git a/demos/time-tracker/protected/pages/Docs/WritingUnitTest.page b/demos/time-tracker/protected/pages/Docs/WritingUnitTest.page
index 32c7bc79..77bdcbe6 100644
--- a/demos/time-tracker/protected/pages/Docs/WritingUnitTest.page
+++ b/demos/time-tracker/protected/pages/Docs/WritingUnitTest.page
@@ -1,13 +1,19 @@
Writing a Unit Test
+Before we begin to write our business logic and code, we shall
+proceed with the path of test driven development (TDD), or at least take
+some part of that process.
+
Unit testing is a useful tool when we want to start to test
our individual business logic classes.
- The tests/unit directory will be used to hold the unit test cases and tests/functional directory
-to hold the function test cases.
+ The tests/unit directory will be used to hold the unit test
+ cases and tests/functional directory
+ to hold the function test cases.
Write a unit test case
-We will start be writing a very simple unit test case.
+We will start be writing a very simple unit test case. Notice
+that we are writing the test case first .
<?php
class ProjectTestCase extends UnitTestCase
@@ -29,14 +35,16 @@ directory.
Figure 1: Unit test runner
-Clicking on the ProjectTestCase.php like, you should see
+
Clicking on the ProjectTestCase.php link, you should see
Figure 2: Unit test failure
Smallest step to make the test pass.
-Obviously, we need create the class Project , so lets define the class.
+Since we only wrote the test case and nothing else we expected
+that the test case will fail at some point. Obviously, we need create
+a class Project , so lets define the Project class.
<?php
class Project
@@ -44,15 +52,11 @@ class Project
}
?>
-Save the above code as time-tracker/protected/pages/APP_CODE/Project.php .
- Where the APP_CODE directory will contain most of your business logic code for the Time Tracker application.
-We also need to add the following line in our test case so as to include the Project class file when running the tests.
-
-
-The statement Prado::using('Application.APP_CODE.Project') basically
-loads the Project.php class file. It assumes that a class name Project has filename Project.php .
-For futher details regarding Prado::using can be found in Prado Namespaces documentation.
-
+We save the above code as time-tracker/protected/pages/APP_CODE/Project.php .
+ Where the APP_CODE directory will contain most of the business logic code
+ for the Time Tracker application.
+Now, we also need to add the following line in our test case so as to
+include the Project class file when running the tests.
<?php
@@ -63,11 +67,20 @@ class ProjectTestCase extends UnitTestCase
}
?>
+
+Info:
+The statement
Prado::using('Application.APP_CODE.Project') basically
+loads the
Project.php class file. It assumes that a class name
Project has filename
Project.php .
+For futher details regarding
Prado::using can be found in
Prado Namespaces documentation.
+
+
Run the unit test runner again, we see that the test has passed.
Figure 3: Unit test success
-Later on, we shall write more test cases. See the SimpleTest documentation for detailed tutorial on writing test cases.
+Later on, we shall write more test cases. See the
+SimpleTest documentation
+for detailed tutorial on writing test cases.
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/Docs/config.xml b/demos/time-tracker/protected/pages/Docs/config.xml
index da4d3bfc..e8fdc3fe 100644
--- a/demos/time-tracker/protected/pages/Docs/config.xml
+++ b/demos/time-tracker/protected/pages/Docs/config.xml
@@ -1,8 +1,12 @@
-
-
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/Docs/db.png b/demos/time-tracker/protected/pages/Docs/db.png
index f2209ef4..efdcc1e5 100644
Binary files a/demos/time-tracker/protected/pages/Docs/db.png and b/demos/time-tracker/protected/pages/Docs/db.png differ
diff --git a/demos/time-tracker/protected/pages/TimeTracker/Login.page b/demos/time-tracker/protected/pages/TimeTracker/Login.page
new file mode 100644
index 00000000..dbc16de1
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/Login.page
@@ -0,0 +1,38 @@
+<%@ Title="My Company - Time Tracker - Site Logon" %>
+
+Time Tracker Website Login
+
+User Login
+
+
+ *
+
+
+
+
+
+ *
+
+
+
+
+
+
+
+
+
+
+
+
Create New User
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/Login.php b/demos/time-tracker/protected/pages/TimeTracker/Login.php
new file mode 100644
index 00000000..376953a5
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/Login.php
@@ -0,0 +1,53 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * Login page class.
+ *
+ * Validate the user credentials and redirect to requested page
+ * if successful.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class Login extends TPage
+{
+ /**
+ * Validates the username and password.
+ * @param TControl custom validator that created the event.
+ * @param TServerValidateEventParameter validation parameters.
+ */
+ public function validateUser($sender, $param)
+ {
+ $authManager=$this->Application->getModule('auth');
+ if(!$authManager->login($this->username->Text,$this->password->Text))
+ $param->IsValid=false;;
+ }
+
+ /**
+ * Redirect to the requested page if login is successful.
+ * @param TControl button control that created the event.
+ * @param TEventParameter event parameters.
+ */
+ public function doLogin($sender, $param)
+ {
+ if($this->Page->IsValid)
+ {
+ $auth = $this->Application->getModule('auth');
+ $this->Response->redirect($auth->getReturnUrl());
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/Logout.page b/demos/time-tracker/protected/pages/TimeTracker/Logout.page
new file mode 100644
index 00000000..e69de29b
diff --git a/demos/time-tracker/protected/pages/TimeTracker/Logout.php b/demos/time-tracker/protected/pages/TimeTracker/Logout.php
new file mode 100644
index 00000000..08fdfaf6
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/Logout.php
@@ -0,0 +1,34 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * Logout page class.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class Logout extends TPage
+{
+ /**
+ * Logs out the current user and redirect to default page.
+ */
+ function onLoad($param)
+ {
+ $this->Application->getModule('auth')->logout();
+ $url = $this->Service->constructUrl($this->Service->DefaultPage);
+ $this->Response->redirect($url);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/MainLayout.php b/demos/time-tracker/protected/pages/TimeTracker/MainLayout.php
new file mode 100644
index 00000000..253d6c03
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/MainLayout.php
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/MainLayout.tpl b/demos/time-tracker/protected/pages/TimeTracker/MainLayout.tpl
new file mode 100644
index 00000000..2d8bad44
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/MainLayout.tpl
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+ Service->constructUrl('TimeTracker.Login') %>
+ Visible=<%= $this->User->getIsGuest() %> />
+ Service->constructUrl('TimeTracker.Logout') %>
+ Visible=<%= !$this->User->getIsGuest() %> />
+
+
+
+
+
+User->getIsGuest() %> />
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/SiteMap.php b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.php
new file mode 100644
index 00000000..0b71eb68
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.php
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
new file mode 100644
index 00000000..48187b52
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Event.OnLoad(function()
+ {
+ menuitems = $$(".menuitem");
+ menuitems.each(function(el)
+ {
+ Event.observe(el, "mouseover", function(ev)
+ {
+ menuitems.each(function(item)
+ {
+ Element.removeClassName(item.parentNode, "active");
+ });
+ Element.addClassName(Event.element(ev).parentNode, "active");
+ });
+ });
+ });
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/UserCreate.page b/demos/time-tracker/protected/pages/TimeTracker/UserCreate.page
new file mode 100644
index 00000000..fda7ba9b
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/UserCreate.page
@@ -0,0 +1,65 @@
+
+Create New User
+
+User Details
+ Sign Up for Your New Account
+
+
+ *
+
+
+
+
+
+
+ *
+
+
+
+
+
+
+ *
+
+
+
+
+
+ *
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/UserCreate.php b/demos/time-tracker/protected/pages/TimeTracker/UserCreate.php
new file mode 100644
index 00000000..b337bfca
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/UserCreate.php
@@ -0,0 +1,78 @@
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ */
+
+/**
+ * Create new user page class. Validate that the usernames are unique
+ * and set the new user credentials as the current application credentials.
+ *
+ * @author Wei Zhuo
+ * @version $Revision: $ $16/07/2006: $
+ * @package Demos
+ * @since 3.1
+ */
+class UserCreate extends TPage
+{
+ /**
+ * Verify that the username is not taken.
+ * @param TControl custom validator that created the event.
+ * @param TServerValidateEventParameter validation parameters.
+ */
+ public function checkUsername($sender, $param)
+ {
+ $userDao = $this->Application->Modules['daos']->getDao('UserDao');
+ $user = $userDao->getUserByName($this->username->Text);
+ if(!is_null($user))
+ {
+ $param->IsValid = false;
+ $sender->ErrorMessage =
+ "The user name is already taken, try '{$user->Name}01'";
+ }
+ }
+
+ /**
+ * Create a new user if all data entered are valid.
+ * The default user roles are obtained from "config.xml". The new user
+ * details is saved to the database and the new credentials are used as the
+ * application user. The user is redirected to the requested page.
+ * @param TControl button control that created the event.
+ * @param TEventParameter event parameters.
+ */
+ public function createNewUser($sender, $param)
+ {
+ if($this->IsValid)
+ {
+ $newUser = new TimeTrackerUser($this->User->Manager);
+ $newUser->EmailAddress = $this->email->Text;
+ $newUser->Name = $this->username->Text;
+ $newUser->IsGuest = false;
+ $newUser->Roles = $this->Application->Parameters['NewUserRoles'];
+
+ //save the user
+ $userDao = $this->Application->Modules['daos']->getDao('UserDao');
+ $userDao->addNewUser($newUser, $this->password->Text);
+
+ //update the user
+ $auth = $this->Application->getModule('auth');
+ $auth->updateSessionUser($newUser);
+ $this->Application->User = $newUser;
+
+ //return to requested page
+ $this->Response->redirect($auth->getReturnUrl());
+
+ //goto default page.
+ //$url = $this->Service->constructUrl($this->Service->DefaultPage);
+ //$this->Response->redirect($url);
+ }
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/UserList.page b/demos/time-tracker/protected/pages/TimeTracker/UserList.page
new file mode 100644
index 00000000..48b2bbc7
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/UserList.page
@@ -0,0 +1,3 @@
+
+List Users
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/config.xml b/demos/time-tracker/protected/pages/TimeTracker/config.xml
new file mode 100644
index 00000000..dac6465d
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/config.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/Welcome.page b/demos/time-tracker/protected/pages/Welcome.page
new file mode 100644
index 00000000..65ada02d
--- /dev/null
+++ b/demos/time-tracker/protected/pages/Welcome.page
@@ -0,0 +1,168 @@
+
+
+
+ Welcome
+
+
+
+ Time Tracker Starter Kit
+
+ Welcome to your new Time Tracker sample application. The key features are:
+
+ Projects. Define project information like due dates, hours to complete,
+ project resources, and more.
+ Track Time. Track time spent each day by category and project.
+ Reports. Generate progress and team resource reports across multiple projects.
+
+
+ The Time Tracker site is ready to run! No changes are needed.
+
+
+
+ Site Members and Roles
+
+ Your Time Tracker Web site allows visitors to register as members and then log in.
+ Members have specific privileges defined by roles such as administrator or guest.
+ Each Time Tracker Web site defines site-specific roles.
+ The following table describes what features are available to visitors in different roles.
+
+
+ Visitor
+ Privileges
+ Default Login
+
+
+
+ Not logged in
+
+ No privileges.
+
+
+
+ Logged in
+
+ No privileges. All members must be associated at least with the role Consultant .
+ N/A
+
+
+ Logged in as
+ Consultant
+ May log time entries only.
+ username: consultant
+ password: consultant
+
+
+
+ Logged in as
+ Project Manager
+
+ May additionally edit all projects and view reports.
+ username: manager
+ password: manager
+
+
+
+ Logged in as
+ Project Administrator
+
+ May additionally view the list of all users.
+ username: admin
+ password: admin
+
+
+
+ Be sure to create a user name for yourself and assign yourself to a role (such as administrator) that can manage the site.
+
+ Visitors can register by clicking the Create new user link on the home page.
+ New members are activated automatically, and are assigned to a role as specified in the application.xml file.
+ You can manage users (for example, assign them to a role) when login as administrator.
+ For details, see Appendix A .
+
+
+
+ Projects and Time Entries
+ To add a project and categories
+
+ Log in to the site as a member in the role Project Manager or Project Administrator .
+ Click the Projects tab and then click Create New Project .
+ Specify a project name, project manager, estimated complete date, estimated duration, and description.
+ Under Specify Project Members , select a resource. You must select at least one resource.
+ Click Save . A category pane is displayed on the right.
+ Specify a category name, category abbreviation, and duration.
+ Click Add . The new category is displayed in the categories list.
+ Repeat steps 6 and 7 to create additional categories.
+
+ Log a Time Entry
+
+ Log in to the site as a consultant (member in the role Consultant ).
+ Click the Log tab.
+ Under Log your hours , choose a project and a category and fill in the day, hours, and description.
+ Make sure the correct consultant is selected in the Time Sheet For list.
+ Click Add Entry .
+
+
+
+
+ Reports
+ To create a project report
+
+ Log in to the site as a member in the role Project Manager or Project Administrator .
+ Click the Reports tab and then click Project Reports .
+ Under Select a project , choose one or more projects.
+ Click Generate Report .
+
+ To create a resource report
+
+ Log in to the site as a member in the role Project Manager or Project Administrator .
+ Click the Reports tab and then click Resources Report .
+ Select one or more projects, select one or more resources, and then specify a date range.
+ Click Generate Report .
+
+
+
+
+
+ Appendix A - Manually Managing Members and Roles
+
+ Your Time Tracker Web site allows visitors to register as members.
+ Members have specific privileges defined by a role you assign to them.
+ A special administrative role has rights to perform all functions in the site.
+
+ To create a user (member):
+
+ Login as administrator, click Create New User .
+
+ ...
+
+
+ To modify an existing member's role:
+
+ Login as administrator, click List Users .
+
+ ...
+
+
+
+
+ Appendix B - Publishing Your Site
+
+ When you are ready to share the Web site with others, you can copy it to your Web server.
+ You need to know the File Transfer Protocol (FTP) address of your server, and if required, the user name and password assigned to you.
+
+ ...
+
+
+
diff --git a/demos/time-tracker/tests/functional.php b/demos/time-tracker/tests/functional.php
index c216ada8..888b29db 100644
--- a/demos/time-tracker/tests/functional.php
+++ b/demos/time-tracker/tests/functional.php
@@ -1,6 +1,6 @@
createNewTestProject();
-
- $user = new TimeTrackerUser();
- $user->ID = 3;
- $user->Name = "test user 1";
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- $this->setupMockConnectionFor($project);
- $conn->setReturnReference('queryForObject', $user, array('GetUserByName', $user->Name));
- $conn->setReturnValue('queryForList', array(), array('GetProjectMembers', $project));
-
- $param['project'] = $project;
- $param['user'] = $user;
-
- $conn->setReturnValue('insert', true, array('AddNewUserToProject', $param));
-
- $conn->expectAtLeastOnce('insert');
- $conn->expectAtLeastOnce('queryForList');
- }
-
- $this->assertTrue($this->dao->createNewProject($project));
- $this->assertTrue($this->dao->addUserToProject($project, $user));
- }
-}
-
-?>
\ No newline at end of file
diff --git a/demos/time-tracker/tests/unit/BaseTestCase.php b/demos/time-tracker/tests/unit/BaseTestCase.php
new file mode 100644
index 00000000..8ce3cca8
--- /dev/null
+++ b/demos/time-tracker/tests/unit/BaseTestCase.php
@@ -0,0 +1,35 @@
+sqlmap = $app->getModule('daos')->getConnection();
+ }
+
+ function flushDatabase()
+ {
+ $conn = $this->sqlmap->openConnection();
+ $file = Prado::getPathOfNamespace('Application.App_Data.mysql-reset','.sql');
+ if(is_file($file))
+ $this->runScript($conn, $file);
+ else
+ throw new Exception('unable to find script file '.$file);
+ }
+
+ protected function runScript($connection, $script)
+ {
+ $sql = file_get_contents($script);
+ $lines = explode(';', $sql);
+ foreach($lines as $line)
+ {
+ $line = trim($line);
+ if(strlen($line) > 0)
+ $connection->execute($line);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/tests/unit/CreateNewProjectTestCase.php b/demos/time-tracker/tests/unit/CreateNewProjectTestCase.php
deleted file mode 100644
index 0aa67405..00000000
--- a/demos/time-tracker/tests/unit/CreateNewProjectTestCase.php
+++ /dev/null
@@ -1,90 +0,0 @@
-createNewTestProject();
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- $this->setupMockConnectionFor($project);
- $conn->expectMinimumCallCount('queryForObject', 3);
- $conn->expectAtLeastOnce('insert');
- }
-
- $this->assertProjectCreated($project);
- }
-
- function testProjectExistsException()
- {
- $project = $this->createNewTestProject();
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- //make the project exist
- $conn->setReturnValue('queryForObject',
- $project, array('GetProjectByName', 'Project 1'));
- $this->setupMockConnectionFor($project);
- }
-
- try
- {
- $this->assertProjectCreated($project);
- $this->fail();
- }
- catch(TimeTrackerException $e)
- {
- $this->pass();
- }
- }
- function testProjectCustomerNotExistsException()
- {
- $project = $this->createNewTestProject();
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- //customer does not exist
- $conn->setReturnValue('queryForObject',
- null, array('GetUserByName', 'Customer A'));
- $this->setupMockConnectionFor($project);
- }
-
- try
- {
- $this->assertProjectCreated($project);
- $this->fail();
- }
- catch(TimeTrackerException $e)
- {
- $this->pass();
- }
- }
-
- function testProjectManagerNotExistsException()
- {
- $project = $this->createNewTestProject();
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- //manager does not exist
- $conn->setReturnValue('queryForObject',
- null, array('GetUserByName', 'Manager A'));
- $this->setupMockConnectionFor($project);
- }
-
- try
- {
- $this->assertProjectCreated($project);
- $this->fail();
- }
- catch(TimeTrackerException $e)
- {
- $this->pass();
- }
- }
-}
-
-?>
\ No newline at end of file
diff --git a/demos/time-tracker/tests/unit/ProjectDaoTestCase.php b/demos/time-tracker/tests/unit/ProjectDaoTestCase.php
deleted file mode 100644
index bc576630..00000000
--- a/demos/time-tracker/tests/unit/ProjectDaoTestCase.php
+++ /dev/null
@@ -1,92 +0,0 @@
-dao= new ProjectDao();
- $this->connection = new MockTSqlMapper($this);
- $this->dao->setConnection($this->connection);
- }
-
-/*
- //Simple test case, will not detect project existanc
- //This case will clash with the more complete test case below.
- function testProjectDaoCanCreateNewProject()
- {
- $project = new Project();
- $project->Name = "Project 1";
-
- if(($conn = $this->connection) instanceof MockTSqlMapper)
- {
- $conn->expectOnce('insert', array('CreateNewProject', $project));
- $conn->setReturnValue('insert', true);
-
- $conn->expectOnce('queryForObject', array('GetProjectByID', 1));
- $conn->setReturnReference('queryForObject', $project);
- }
-
- $this->assertTrue($this->dao->createNewProject($project));
- $this->assertEqual($this->dao->getProjectByID(1), $project);
- }
-*/
- function setupMockConnectionFor($project)
- {
- $customer = new TimeTrackerUser();
- $customer->ID = 1;
- $customer->Name = "Customer A";
-
- $manager = new TimeTrackerUser();
- $manager->ID = 2;
- $manager->Name = "Manager A";
-
- $conn = $this->connection;
-
- //return the customer and manager
- $conn->setReturnValue('queryForObject',
- $customer, array('GetUserByName', 'Customer A'));
- $conn->setReturnValue('queryForObject',
- $manager, array('GetUserByName', 'Manager A'));
-
- //project does not exist
- $conn->setReturnValue('queryForObject',
- null, array('GetProjectByName', 'Project 1'));
-
- $param['project'] = $project;
- $param['creator'] = $customer->ID;
- $param['manager'] = $manager->ID;
-
- $conn->setReturnValue('insert',
- true, array('CreateNewProject', $param));
- $conn->setReturnReference('queryForObject',
- $project, array('GetProjectByID', 1));
- }
-
- function createNewTestProject()
- {
- $project = new Project();
- $project->Name = "Project 1";
- $project->CreatorUserName = "Customer A";
- $project->ManagerUserName = "Manager A";
-
- return $project;
- }
-
- function assertProjectCreated($project)
- {
- $this->assertTrue($this->dao->createNewProject($project));
- $this->assertEqual($this->dao->getProjectByID(1), $project);
- }
-
-}
-?>
\ No newline at end of file
diff --git a/demos/time-tracker/tests/unit/ProjectTestCase.php b/demos/time-tracker/tests/unit/ProjectTestCase.php
index a61c4f77..59f612bd 100644
--- a/demos/time-tracker/tests/unit/ProjectTestCase.php
+++ b/demos/time-tracker/tests/unit/ProjectTestCase.php
@@ -3,13 +3,17 @@
//import Project class.
Prado::using('Application.APP_CODE.Project');
-class ProjectTestCase extends UnitTestCase
+require_once(dirname(__FILE__).'/BaseTestCase.php');
+
+class ProjectTestCase extends BaseTestCase
{
function testProjectClassExists()
{
$project = new Project();
$this->pass();
}
+
+
}
?>
\ No newline at end of file
diff --git a/demos/time-tracker/tests/unit/UserDaoTestCase.php b/demos/time-tracker/tests/unit/UserDaoTestCase.php
new file mode 100644
index 00000000..d1f3c728
--- /dev/null
+++ b/demos/time-tracker/tests/unit/UserDaoTestCase.php
@@ -0,0 +1,283 @@
+userDao = $app->getModule('daos')->getDao('UserDao');
+ }
+
+ function assertIsAdmin($user)
+ {
+ if(!$user)
+ return $this->fail();
+ $this->assertEqual($user->getName(), 'admin');
+ $this->assertEqual($user->getEmailAddress(), 'admin@pradosoft.com');
+ }
+
+ function assertSameUser($user1, $user2)
+ {
+ if(is_null($user1) || is_null($user2))
+ return $this->fail();
+
+ $this->assertEqual($user1->getName(), $user2->getName());
+ $this->assertEqual($user1->getEmailAddress(), $user2->getEmailAddress());
+ }
+
+ function assertIsAdminRole($user)
+ {
+ if(is_null($user))
+ return $this->fail();
+
+ $this->assertTrue($user->isInRole('admin'));
+ }
+
+ function assertIsManagerRole($user)
+ {
+ if(is_null($user))
+ return $this->fail();
+
+ $this->assertTrue($user->isInRole('manager'));
+ }
+
+ function assertIsConsultantRole($user)
+ {
+ if(is_null($user))
+ return $this->fail();
+
+ $this->assertTrue($user->isInRole('consultant'));
+ }
+
+ function assertNotConsultantRole($user)
+ {
+ if(is_null($user))
+ return $this->fail();
+
+ $this->assertFalse($user->isInRole('consultant'));
+ }
+
+ function testGetUserByName()
+ {
+ $user = $this->userDao->getUserByName('admin');
+ $this->assertNotNull($user);
+ $this->assertIsAdmin($user);
+ }
+
+ function testGetNonExistentUser()
+ {
+ $user = $this->userDao->getUserByName('none');
+ $this->assertNull($user);
+ }
+
+ function testGetUsers()
+ {
+ $users = $this->userDao->getAllUsers();
+ $this->assertEqual(count($users), 3);
+ }
+
+ function testUserLogon()
+ {
+ $success = $this->userDao->validateUser('admin', 'admin');
+ $this->assertTrue($success);
+ }
+
+ function testBadLogin()
+ {
+ $success = $this->userDao->validateUser('admin', 'hahah');
+ $this->assertFalse($success);
+ }
+
+
+ function testAddNewUser()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "user1";
+ $user->EmailAddress = 'user1@pradosoft.com';
+
+ $this->userDao->addNewUser($user, 'password');
+
+ $check = $this->userDao->getUserByName($user->Name);
+
+ $this->assertSameUser($check, $user);
+ $this->flushDatabase();
+ }
+
+ function testDeleteUserByName()
+ {
+ $this->userDao->deleteUserByName('admin');
+
+ $admin = $this->userDao->getUserByName('admin');
+ $this->assertNull($admin);
+
+ $users = $this->userDao->getAllUsers();
+ $this->assertEqual(count($users), 2);
+
+ $this->flushDatabase();
+ }
+
+ function testAutoSignon()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "admin";
+
+ $token = $this->userDao->createSignonToken($user);
+
+ $check = $this->userDao->validateSignon($token);
+
+ $this->assertIsAdmin($check);
+
+ $this->flushDatabase();
+ }
+
+
+ function testBadAutoSignon()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "admin";
+
+ $token = $this->userDao->createSignonToken($user);
+
+ $check = $this->userDao->validateSignon('adasd');
+ $this->assertNull($check);
+
+ $this->flushDatabase();
+ }
+
+ function testAdminRoles()
+ {
+ $user = $this->userDao->getUserByName('admin');
+ $this->assertIsAdminRole($user);
+ $this->assertIsManagerRole($user);
+ $this->assertIsConsultantRole($user);
+ }
+
+ function testSetUserRoles()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "user1";
+ $user->EmailAddress = 'user1@pradosoft.com';
+ $user->Roles = array("manager", "consultant");
+
+ $this->userDao->addNewUser($user, 'password');
+ $check = $this->userDao->getUserByName('user1');
+
+ $this->assertIsManagerRole($check);
+ $this->assertIsConsultantRole($check);
+
+ $this->flushDatabase();
+ }
+
+ function testSetUserRoleNoNullUser()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "user1";
+ $user->EmailAddress = 'user1@pradosoft.com';
+ $user->Roles = array("manager", "consultant");
+
+ try
+ {
+ $this->userDao->updateUserRoles($user);
+ $this->fail();
+ }
+ catch(TDataMapperException $e)
+ {
+ $this->pass();
+ }
+
+ $check = $this->sqlmap->queryForObject('GetUserByName', 'user1');
+ $this->assertNull($check);
+ }
+
+ function testUpdateUser()
+ {
+ $user = $this->userDao->getUserByName('admin');
+ $user->EmailAddress = 'something@pradosoft.com';
+ $user->Roles = array('manager', 'admin');
+
+ $this->userDao->updateUser($user);
+
+ $check = $this->userDao->getUserByName('admin');
+ $this->assertIsAdminRole($check);
+ $this->assertIsManagerRole($check);
+ $this->assertNotConsultantRole($check);
+
+ $this->flushDatabase();
+ }
+
+ function testUpdateUserPassword()
+ {
+ $user = $this->userDao->getUserByName('admin');
+ $user->EmailAddress = 'something@pradosoft.com';
+ $user->Roles = array('manager', 'admin');
+
+ $pass = 'newpasword';
+
+ $this->userDao->updateUser($user, $pass);
+
+ $success = $this->userDao->validateUser('admin', $pass);
+
+ $this->assertTrue($success);
+
+ $this->flushDatabase();
+ }
+
+ function testClearSignonTokens()
+ {
+ $user = new TimeTrackerUser(new UserManager());
+ $user->Name = "admin";
+
+ $token1 = $this->userDao->createSignonToken($user);
+ sleep(1);
+ $token2 = $this->userDao->createSignonToken($user);
+ $this->assertNotEqual($token1, $token2);
+
+ $check1 = $this->userDao->validateSignon($token1);
+ $check2 = $this->userDao->validateSignon($token2);
+
+ $this->assertIsAdmin($check1);
+ $this->assertIsAdmin($check2);
+
+ $this->userDao->clearSignonTokens($user);
+
+ $check3 = $this->userDao->validateSignon($token1);
+ $check4 = $this->userDao->validateSignon($token2);
+
+ $this->assertNull($check3);
+ $this->assertNull($check4);
+ }
+
+ function testClearAllSigonTokens()
+ {
+ $user1 = new TimeTrackerUser(new UserManager());
+ $user1->Name = "admin";
+
+ $user2 = new TimeTrackerUser(new UserManager());
+ $user2->Name = "manager";
+
+ $token1 = $this->userDao->createSignonToken($user1);
+ $token2 = $this->userDao->createSignonToken($user2);
+
+ $check1 = $this->userDao->validateSignon($token1);
+ $check2 = $this->userDao->validateSignon($token2);
+
+ $this->assertIsAdmin($check1);
+ $this->assertNotNull($check2);
+ $this->assertEqual($check2->Name, $user2->Name);
+
+ $this->userDao->clearSignonTokens();
+
+ $check3 = $this->userDao->validateSignon($token1);
+ $check4 = $this->userDao->validateSignon($token2);
+
+ $this->assertNull($check3);
+ $this->assertNull($check4);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/demos/time-tracker/themes/TimeTracker/background.png b/demos/time-tracker/themes/TimeTracker/background.png
new file mode 100644
index 00000000..ad339daf
Binary files /dev/null and b/demos/time-tracker/themes/TimeTracker/background.png differ
diff --git a/demos/time-tracker/themes/TimeTracker/site.css b/demos/time-tracker/themes/TimeTracker/site.css
new file mode 100644
index 00000000..f426243e
--- /dev/null
+++ b/demos/time-tracker/themes/TimeTracker/site.css
@@ -0,0 +1,217 @@
+html
+{
+ background-color: #eef;
+}
+body
+{
+ background: url(background.png) repeat-x top;
+ margin: 0;
+ padding: 2em;
+ font-family: Tahoma, Arial, Helvetica, sans-serif;
+}
+
+h1, h2, h3, h4
+{
+ color: #6495ED;
+}
+
+div.main
+{
+
+ background-color: White;
+ padding: 30px 30px 200px 30px;
+ margin-top: 1.8em;
+ -moz-border-radius: 15px 15px 0 0;
+}
+
+h1.heading, h1 a
+{
+ color: white;
+ text-decoration: none;
+ margin: -1.2em 0 1em 0;
+ font-size: 1.25em;
+}
+
+h1.heading, h1 a:hover
+{
+ color: white;
+}
+
+h1 .subheading
+{
+ display: block;
+ font-size: 0.96em;
+ color: #E0FFFF;
+}
+
+.minheading
+{
+ text-align: right;
+ margin-top: -3.5em;
+}
+.minheading h2
+{
+ font-size: 0.9em;
+ display: inline;
+ padding-left: 1em;
+}
+
+.minheading .name
+{
+ color: white;
+ margin-right: 1em;
+}
+
+.minheading a
+{
+ color: white;
+}
+
+.minheading a:hover
+{
+ color: Yellow;
+}
+
+a
+{
+ color: #f61;
+}
+
+a:hover
+{
+ color: red;
+}
+
+/** menu **/
+
+.sitemap
+{
+ text-align: center;
+ margin-top: 1.5em;
+ margin-bottom: -1.5em;
+}
+
+ul.level1
+{
+
+}
+
+ul.level1, ul.level2
+{
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul.level1 li
+{
+ display: inline;
+}
+ul.level1 li .menuitem
+{
+ padding: 0.3em 20px 0.3em 20px;
+ background-color: #B6CEF7;
+ cursor: pointer;
+ background-image: url(tabs.png);
+ background-repeat: repeat-x;
+ color: #f71;
+ font-weight: bold;
+ letter-spacing: 2px;
+}
+
+ul.level1 li.active .menuitem
+{
+ background-color: White;
+ background-image: none;
+}
+
+ul.level2
+{
+ display: none;
+}
+
+li.active ul.level2
+{
+ float: left;
+ display: block;
+ width: 95%;
+ margin: 1em 0 0 0;
+ padding-bottom: 1em;
+}
+
+li.active ul.level2 li a
+{
+ margin-left: 1em;
+ color: #f61;
+ text-decoration: none;
+ border-bottom:1px dashed #f61;
+}
+
+li.active ul.level2 li a:hover
+{
+ color: Red;
+}
+
+
+/** forms **/
+
+fieldset.login, fieldset.signup
+{
+ margin: 0;
+ border: 1px solid #6495ED;
+ padding: 1.5em;
+}
+
+fieldset legend
+{
+ font-weight: bold;
+ color: #4169E1;
+ padding: 0.5em;
+}
+
+fieldset.login label, fieldset.signup label
+{
+ float: left;
+ color: #708090;
+ width: 120px;
+ text-align: right;
+}
+
+fieldset.signup label
+{
+ width: 9em;
+}
+
+fieldset span.required
+{
+ font-size: 0.85em;
+ font-weight: bold;
+ color: Red;
+}
+
+fieldset.login div, fieldset.signup div
+{
+ padding: 0.25em;
+}
+
+fieldset.login .remember label
+{
+ float:none;
+ margin-left: 0.4em;
+}
+fieldset.login .remember input
+{
+ margin-left: 133px;
+}
+
+fieldset.login .signin input
+{
+ padding: 0.1em 2em;
+ margin-left: 133px;
+}
+
+fieldset.signup .create
+{
+ margin: 1em;
+ padding-left: 9em;
+}
\ No newline at end of file
diff --git a/demos/time-tracker/themes/TimeTracker/tabs.png b/demos/time-tracker/themes/TimeTracker/tabs.png
new file mode 100644
index 00000000..7f1ca0bb
Binary files /dev/null and b/demos/time-tracker/themes/TimeTracker/tabs.png differ
diff --git a/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php b/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php
index ee8f1744..2441dedf 100644
--- a/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php
+++ b/framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php
@@ -104,6 +104,7 @@ class TConfigDeserialize
public function resultMap($node, $sqlMap, $file)
{
$resultMap = new TResultMap;
+ $resultMap->initialize($sqlMap);
$this->loadConfiguration($resultMap, $node, $file);
foreach($node->result as $result)
{
diff --git a/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
index d3059dd7..ba8323cc 100644
--- a/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
+++ b/framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php
@@ -63,6 +63,9 @@ class TDomSqlMapBuilder
if(isset($document->settings) && isset($document->settings->setting))
$this->configureSettings($document->settings);
+
+ if(isset($document->typeHandler))
+ $this->loadTypeHandler($document, $this->_configFile);
//load database provider
if(isset($document->provider) && isset($document->provider->datasource))
@@ -157,11 +160,19 @@ class TDomSqlMapBuilder
{
//$id = (string)$node['id'];
$class = (string)$providerNode['class'];
- if(strlen($class) > 0 && class_exists($class,false))
+ if(strlen($class) > 0)
{
- $provider = new $class;
- $this->_deserialize->loadConfiguration($provider, $node,$file);
- $this->_sqlMapper->setDataProvider($provider);
+ if(class_exists($class,false))
+ {
+ $provider = new $class;
+ $this->_deserialize->loadConfiguration($provider, $node,$file);
+ $this->_sqlMapper->setDataProvider($provider);
+ }
+ else
+ {
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_unable_find_provider_class_def', $file, $class);
+ }
}
else
{
@@ -170,11 +181,38 @@ class TDomSqlMapBuilder
}
//var_dump($node);
}
-/*
- protected function loadTypeHandlers()
+
+ protected function loadTypeHandler($nodes, $file)
{
+ foreach($nodes->typeHandler as $node)
+ {
+ if(!is_null($node['type']) && !is_null($node['callback']))
+ {
+ $type = (string)$node['type'];
+ $class = (string)$node['callback'];
+ if(class_exists('Prado', false))
+ {
+ $handler = Prado::createComponent($class);
+ }
+ else
+ {
+ if(class_exists($class,false))
+ $handler = new $class;
+ else
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_type_handler_class_undef', $file, $class);
+ }
+ $factory = $this->_sqlMapper->getTypeHandlerFactory();
+ $factory->register($type, $handler);
+ }
+ else
+ {
+ throw new TSqlMapConfigurationException(
+ 'sqlmap_type_handler_callback_undef', $file);
+ }
+ }
}
-*/
+
protected function loadSqlMappingFiles($sqlmappings)
{
foreach($sqlmappings->sqlMap as $node)
diff --git a/framework/DataAccess/SQLMap/Configuration/TParameterMap.php b/framework/DataAccess/SQLMap/Configuration/TParameterMap.php
index 8e1c757d..b3c6ed6e 100644
--- a/framework/DataAccess/SQLMap/Configuration/TParameterMap.php
+++ b/framework/DataAccess/SQLMap/Configuration/TParameterMap.php
@@ -56,7 +56,7 @@ class TParameterMap extends TComponent
$typeHandler = $mapping->getTypeHandler();
try
{
- $value = TPropertyAccess::get($parameterValue, $mapping->getProperty());
+ $value = TPropertyAccess::get($parameterValue, $mapping->getProperty());
}
catch (TInvalidPropertyException $e)
{
diff --git a/framework/DataAccess/SQLMap/Configuration/TResultMap.php b/framework/DataAccess/SQLMap/Configuration/TResultMap.php
index 0f09a1ba..b8032c81 100644
--- a/framework/DataAccess/SQLMap/Configuration/TResultMap.php
+++ b/framework/DataAccess/SQLMap/Configuration/TResultMap.php
@@ -8,6 +8,7 @@ class TResultMap extends TComponent
private $_extendMap='';
private $_groupBy='';
private $_discriminator=null;
+ private $_typeHandlerFactory=null;
public function __construct()
{
@@ -32,6 +33,11 @@ class TResultMap extends TComponent
public function getDiscriminator(){ return $this->_discriminator; }
public function setDiscriminator($value){ $this->_discriminator = $value; }
+ public function initialize($sqlMap, $resultMap=null)
+ {
+ $this->_typeHandlerFactory = $sqlMap->getTypeHandlerFactory();
+ }
+
public function addResultProperty(TResultProperty $property)
{
$this->_columns->add($property->getProperty(), $property);
@@ -39,7 +45,21 @@ class TResultMap extends TComponent
public function createInstanceOfResult()
{
- return TTypeHandlerFactory::createInstanceOf($this->getClass());
+ $handler = $this->_typeHandlerFactory->getTypeHandler($this->getClass());
+
+ try
+ {
+ if(!is_null($handler))
+ return $handler->createNewInstance();
+ else
+ return TTypeHandlerFactory::createInstanceOf($this->getClass());
+ }
+ catch (TDataMapperException $e)
+ {
+ throw new TSqlMapExecutionException(
+ 'sqlmap_unable_to_create_new_instance',
+ $this->getClass(), get_class($handler), $this->getID());
+ }
}
public function resolveSubMap($row)
diff --git a/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php b/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php
index 228b37d6..414ad2f1 100644
--- a/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php
+++ b/framework/DataAccess/SQLMap/Configuration/TSqlMapStatement.php
@@ -79,14 +79,14 @@ class TSqlMapStatement extends TComponent
return array(); //new TList;
}
- protected function createInstanceOf($type)
+ protected function createInstanceOf($type,$row=null)
{
$handler = $this->_typeHandler->getTypeHandler($type);
try
{
if(!is_null($handler))
- return $handler->createNewInstance();
+ return $handler->createNewInstance($row);
else
return TTypeHandlerFactory::createInstanceOf($type);
}
@@ -99,10 +99,10 @@ class TSqlMapStatement extends TComponent
}
- public function createInstanceOfResultClass()
+ public function createInstanceOfResultClass($row)
{
if(strlen($type= $this->getResultClass()) > 0)
- return $this->createInstanceOf($type);
+ return $this->createInstanceOf($type,$row);
}
}
diff --git a/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
index 4bbe2cb5..e4f5c1fa 100644
--- a/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
+++ b/framework/DataAccess/SQLMap/DataMapper/TPropertyAccess.php
@@ -39,7 +39,7 @@ class TPropertyAccess
*/
public static function get($object,$path)
{
- if(!is_array($object) || !is_object($object))
+ if(!is_array($object) && !is_object($object))
return $object;
$properties = explode('.', $path);
foreach($properties as $prop)
@@ -49,7 +49,7 @@ class TPropertyAccess
if(isset($object[$prop]))
$object = $object[$prop];
else
- throw new TInvalidPropertyException('sqlmap_invalid_property',$path);
+ throw new TInvalidPropertyException('sqlmap_invalid_property',$path);
}
else if(is_object($object))
{
@@ -69,7 +69,7 @@ class TPropertyAccess
public static function has($object, $path)
{
- if(!is_array($object) || !is_object($object))
+ if(!is_array($object) && !is_object($object))
return false;
$properties = explode('.', $path);
foreach($properties as $prop)
diff --git a/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php b/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php
index fcadea28..55fb1f20 100644
--- a/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php
+++ b/framework/DataAccess/SQLMap/DataMapper/TTypeHandlerFactory.php
@@ -55,8 +55,10 @@ class TTypeHandlerFactory
case 'integer': case 'int': return 0;
case 'bool': case 'boolean': return false;
}
-
- if(class_exists($type, false)) //NO auto loading
+
+ if(class_exists('Prado', false))
+ return Prado::createComponent($type);
+ else if(class_exists($type, false)) //NO auto loading
return new $type;
else
throw new TDataMapperException('sqlmap_unable_to_find_class', $type);
@@ -125,10 +127,10 @@ interface ITypeHandlerCallback
* for this type (e.g. File type), you can simply return the String representation
* as it was passed in. It is not recommended to return null, unless null was passed
* in.
- * @param string nullValue.
+ * @param array result row.
* @return mixed
*/
- public function createNewInstance();
+ public function createNewInstance($row=null);
}
?>
\ No newline at end of file
diff --git a/framework/DataAccess/SQLMap/DataMapper/messages.txt b/framework/DataAccess/SQLMap/DataMapper/messages.txt
index 6bf5f396..16be9c2b 100644
--- a/framework/DataAccess/SQLMap/DataMapper/messages.txt
+++ b/framework/DataAccess/SQLMap/DataMapper/messages.txt
@@ -17,6 +17,8 @@ map_item_unremovable = The item cannot be removed from the map.
map_data_not_iterable = Data must be either an array or an object implementing Traversable interface.
map_readonly = {0} is read-only.
+sqlmap_type_handler_class_undef = Unable to find type handler class named '{1}' in sqlmap configuration file '{0}'.
+sqlmap_type_handler_callback_undef = Attributes 'type' and 'callback' must be defined in typeHandler tag in configuration file '{0}'.
sqlmap_contains_no_statement = Unable to find SQLMap statement '{0}'.
sqlmap_already_contains_statement = Duplicate SQLMap statement found, '{0}' already exists.
sqlmap_contains_no_result_map = Unable to find SQLMap result map '{0}'.
@@ -27,6 +29,7 @@ sqlmap_connection_already_exists = SqlMap could not invoke OpenConnection(). A
sqlmap_unable_to_close_null_connection = SqlMap could not invoke CloseConnection(). No connection was started. Call OpenConnection() first.
sqlmap_undefined_attribute = {0} attribute '{1}' is not defined for {2} in file {3}.
sqlmap_unable_find_provider_class = Unable to find a database provider in SQLMap configuration file {0}.
+sqlmap_unable_find_provider_class_def = Unable to load class database provider '{1}' in SQLMap configuration file {0}.
sqlmap_unable_to_find_parent_parameter_map = Unable to find parent parameter map extension '{0}' in file {1}.
sqlmap_unable_to_find_parent_sql = Unable to find parent sql statement extension '{0}' in file {1}.
sqlmap_unable_to_find_result_mapping = Unable to resolve SQLMap result mapping '{0}' in Result Map '{2}' using configuration file {1}.
@@ -36,11 +39,11 @@ sqlmap_index_must_be_string_or_int = Invalid index '{0}', must be an integes or
sqlmap_undefined_input_property = Undefined array index '{0}' in retrieving property in SQLMap parameter map '{1}'.
sqlmap_unable_to_find_class = Unable to find result class '{0}' in TResultMap::createInstanceOfResult().
sqlmap_can_not_instantiate = Type handler '{0}' can not create new objects.
-sqlmap_cannot_execute_query_for_map = SQLMap statement class {0} can not query for map.
-sqlmap_cannot_execute_update = SQLMap statement class {0} can not execute update query.
-sqlmap_cannot_execute_insert = SQLMap statement class {0} can not execute insert.
-sqlmap_cannot_execute_query_for_list = SQLMap statement class {0} can not query for list.
-sqlmap_cannot_execute_query_for_object = SQLMap statement class {0} can not query for object
+sqlmap_cannot_execute_query_for_map = SQLMap statement class {0} can not query for map in statement '{1}'.
+sqlmap_cannot_execute_update = SQLMap statement class {0} can not execute update query in statement '{1}'.
+sqlmap_cannot_execute_insert = SQLMap statement class {0} can not execute insert in statement '{1}'.
+sqlmap_cannot_execute_query_for_list = SQLMap statement class {0} can not query for list in statement '{1}'.
+sqlmap_cannot_execute_query_for_object = SQLMap statement class {0} can not query for object in statement '{1}'.
sqlmap_execution_error_no_record = No record set found in executing statement '{0}': '{1}'.
sqlmap_unable_to_create_new_instance = Unable to create a new instance of '{0}' using type hander '{1}' for SQLMap statement with ID '{2}'.
sqlmap_invalid_property = Invalid property getter path '{0}'.
diff --git a/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php
index 7a444c89..51731a5c 100644
--- a/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php
+++ b/framework/DataAccess/SQLMap/Statements/TInsertMappedStatement.php
@@ -6,26 +6,26 @@ class TInsertMappedStatement extends TMappedStatement
$keyProperty, $valueProperty=null)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_map', get_class($this));
+ 'sqlmap_cannot_execute_query_for_map', get_class($this), $this->getID());
}
public function executeUpdate($connection, $parameter)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_update', get_class($this));
+ 'sqlmap_cannot_execute_update', get_class($this), $this->getID());
}
public function executeQueryForList($connection, $parameter, $result,
$skip=-1, $max=-1)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_list', get_class($this));
+ 'sqlmap_cannot_execute_query_for_list', get_class($this), $this->getID());
}
public function executeQueryForObject($connection, $parameter, $result)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_object', get_class($this));
+ 'sqlmap_cannot_execute_query_for_object', get_class($this), $this->getID());
}
}
diff --git a/framework/DataAccess/SQLMap/Statements/TMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
index 483a315a..c621f285 100644
--- a/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
+++ b/framework/DataAccess/SQLMap/Statements/TMappedStatement.php
@@ -375,18 +375,23 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @return object the object.
* @see executeQueryForObject()
*/
- public function runQueryForObject($connection, $sql, $result)
+ public function runQueryForObject($connection, $sql, &$result)
{
$recordSet = $this->executeSQLQuery($connection, $sql);
- $object = $this->applyResultMap($recordSet->fetchRow(), $result);
- //get group by result
+ $object = null;
+
+ while($row = $recordSet->fetchRow())
+ $object = $this->applyResultMap($row, $result);
+
foreach($this->getGroupbyResults() as $group)
$object = $group->updateProperties();
+
$this->clearGroupByResults();
$this->executePostSelect($connection);
$this->onExecuteQuery($sql);
+
return $object;
}
@@ -403,7 +408,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
$sql = $this->_command->create($connection, $this->_statement, $parameter);
- $this->executeSQLQuery($connection, $sql);
+ $result = $this->executeSQLQuery($connection, $sql);
if(is_null($generatedKey))
$generatedKey = $this->getPostGeneratedSelectKey($connection, $parameter);
@@ -525,7 +530,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @param object the result object, will create if necessary.
* @return object the result filled with data, null if not filled.
*/
- protected function applyResultMap($row, $resultObject=null)
+ protected function applyResultMap($row, &$resultObject=null)
{
if($row === false) return null;
@@ -550,7 +555,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
protected function fillResultClass($resultClass, $row, $resultObject)
{
if(is_null($resultObject))
- $resultObject = $this->_statement->createInstanceOfResultClass();
+ $resultObject = $this->_statement->createInstanceOfResultClass($row);
if($resultObject instanceOf ArrayAccess)
return $this->fillResultArrayList($row, $resultObject);
@@ -608,14 +613,13 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @param object result object to fill, will create new instances if required.
* @return object result object filled with data.
*/
- protected function fillResultMap($resultMapName, $row, $resultObject)
+ protected function fillResultMap($resultMapName, $row, &$resultObject)
{
$resultMap = $this->_sqlMap->getResultMap($resultMapName);
$resultMap = $resultMap->resolveSubMap($row);
if(is_null($resultObject))
$resultObject = $resultMap->createInstanceOfResult();
-
if(is_object($resultObject))
{
if(strlen($resultMap->getGroupBy()) > 0)
@@ -641,21 +645,41 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @see getGroupByResults()
* @see runQueryForList()
*/
- protected function addResultMapGroupBy($resultMap, $row, $resultObject)
+ protected function addResultMapGroupBy($resultMap, $row, &$resultObject)
{
$group = $this->getResultMapGroupKey($resultMap, $row, $resultObject);
+
foreach($resultMap->getColumns() as $property)
{
- $this->setObjectProperty($resultMap, $property, $row, $resultObject);
+ $scalar = $this->setObjectProperty($resultMap, $property, $row, $resultObject);
if(strlen($property->getResultMapping()) > 0)
{
$key = $property->getProperty();
- $value = TPropertyAccess::get($resultObject, $key);
- $this->_groupBy[$group]->addValue($key, $value);
+ $value = $this->extractGroupByValue($property, $resultObject);
+ if(!empty($value))
+ $this->_groupBy[$group]->addValue($key, $value);
}
}
+
return null;
}
+
+ /**
+ * Extract value from the object for later adding to a GroupBy collection.
+ * @param TResultProperty result property
+ * @param mixed result object
+ * @return mixed collection element
+ */
+ protected function extractGroupByValue($property, $resultObject)
+ {
+ $key = $property->getProperty();
+ $value = TPropertyAccess::get($resultObject, $key);
+ $type = strtolower($property->getType());
+ if(($type == 'array' || $type == 'map') && is_array($value) && count($value) == 1)
+ return $value[0];
+ else
+ return $value;
+ }
/**
* Gets the result 'group by' groupping key for each row.
@@ -747,7 +771,7 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @param array a result set row retrieved from the database
* @param object the result object
*/
- protected function setObjectProperty($resultMap, $property, $row, $resultObject)
+ protected function setObjectProperty($resultMap, $property, $row, &$resultObject)
{
$select = $property->getSelect();
$key = $property->getProperty();
@@ -756,8 +780,12 @@ class TMappedStatement extends TComponent implements IMappedStatement
if(strlen($select) == 0 && is_null($nested))
{
$value = $property->getDatabaseValue($row);
- TPropertyAccess::set($resultObject, $key, $value);
+
$this->_IsRowDataFound = $this->_IsRowDataFound || ($value != null);
+ if(is_array($resultObject) || is_object($resultObject))
+ TPropertyAccess::set($resultObject, $key, $value);
+ else
+ $resultObject = $value;
}
else if(!is_null($nested))
{
@@ -844,12 +872,12 @@ class TMappedStatement extends TComponent implements IMappedStatement
* @param object the result object
* @return boolean true if the data was found, false otherwise.
*/
- protected function fillPropertyWithResultMap($resultMap, $row, $resultObject)
+ protected function fillPropertyWithResultMap($resultMap, $row, &$resultObject)
{
$dataFound = false;
foreach($resultMap->getColumns() as $property)
{
- $this->_IsRowDataFound = false;
+ $this->_IsRowDataFound = false;
$this->setObjectProperty($resultMap, $property, $row, $resultObject);
$dataFound = $dataFound || $this->_IsRowDataFound;
}
diff --git a/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php
index 1171e28f..b6f179c0 100644
--- a/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php
+++ b/framework/DataAccess/SQLMap/Statements/TSelectMappedStatement.php
@@ -5,13 +5,13 @@ class TSelectMappedStatement extends TMappedStatement
public function executeInsert($connection, $parameter)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_insert', get_class($this));
+ 'sqlmap_cannot_execute_insert', get_class($this), $this->getID());
}
public function executeUpdate($connection, $parameter)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_update', get_class($this));
+ 'sqlmap_cannot_execute_update', get_class($this), $this->getID());
}
}
diff --git a/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php b/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php
index cf16ee52..353f4b26 100644
--- a/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php
+++ b/framework/DataAccess/SQLMap/Statements/TUpdateMappedStatement.php
@@ -5,27 +5,27 @@ class TUpdateMappedStatement extends TMappedStatement
public function executeInsert($connection, $parameter)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_insert', get_class($this));
+ 'sqlmap_cannot_execute_insert', get_class($this), $this->getID());
}
public function executeQueryForMap($connection, $parameter, $keyProperty,
$valueProperty=null)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_map', get_class($this));
+ 'sqlmap_cannot_execute_query_for_map', get_class($this), $this->getID());
}
public function executeQueryForList($connection, $parameter, $result,
$skip=-1, $max=-1)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_list', get_class($this));
+ 'sqlmap_cannot_execute_query_for_list', get_class($this), $this->getID());
}
public function executeQueryForObject($connection, $parameter, $result)
{
throw new TSqlMapExecutionException(
- 'sqlmap_cannot_execute_query_for_object', get_class($this));
+ 'sqlmap_cannot_execute_query_for_object', get_class($this), $this->getID());
}
}
diff --git a/tests/unit/SQLMap/BaseTest.php b/tests/unit/SQLMap/BaseTest.php
index ebff9c6d..0f3ce1e2 100644
--- a/tests/unit/SQLMap/BaseTest.php
+++ b/tests/unit/SQLMap/BaseTest.php
@@ -175,7 +175,7 @@ class HundredsBool implements ITypeHandlerCallback
return 200;
}
- public function createNewInstance()
+ public function createNewInstance($data=null)
{
throw new TDataMapperException('can not create');
}
@@ -203,7 +203,7 @@ class OuiNonBool implements ITypeHandlerCallback
return self::NO;
}
- public function createNewInstance()
+ public function createNewInstance($data=null)
{
throw new TDataMapperException('can not create');
}
@@ -225,7 +225,7 @@ class TDateTimeHandler implements ITypeHandlerCallback
return $parameter;
}
- public function createNewInstance()
+ public function createNewInstance($data=null)
{
return new TDateTime;
}
diff --git a/tests/unit/SQLMap/InheritanceTest.php b/tests/unit/SQLMap/InheritanceTest.php
index 24e9f987..9ace1c29 100644
--- a/tests/unit/SQLMap/InheritanceTest.php
+++ b/tests/unit/SQLMap/InheritanceTest.php
@@ -138,7 +138,7 @@ class CustomInheritance implements ITypeHandlerCallback
throw new TDataMapperException('not implemented');
}
- public function createNewInstance()
+ public function createNewInstance($data=null)
{
throw new TDataMapperException('can not create');
}
diff --git a/tests/unit/SQLMap/sqlite/tests.db b/tests/unit/SQLMap/sqlite/tests.db
index fa66b2cc..380ef8fa 100644
Binary files a/tests/unit/SQLMap/sqlite/tests.db and b/tests/unit/SQLMap/sqlite/tests.db differ
--
cgit v1.2.3