summaryrefslogtreecommitdiff
path: root/demos/sqlmap/protected/pages/Manual/Tutorial
diff options
context:
space:
mode:
authorwei <>2006-07-16 06:19:36 +0000
committerwei <>2006-07-16 06:19:36 +0000
commitc7d41e5bea4a5f96979a08da9cc9f79355edfe70 (patch)
tree8f21cba052c1eae7c7204ac272dd8c5e9d6fe110 /demos/sqlmap/protected/pages/Manual/Tutorial
parentaf68030fcf0c266300feb2c100149ecadef7d364 (diff)
Update Time Tracker demo.
Diffstat (limited to 'demos/sqlmap/protected/pages/Manual/Tutorial')
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/TestAgain.page214
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/TestFirst.page238
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/TestSecond.page116
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/example1.pngbin0 -> 236887 bytes
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/grid1.pngbin0 -> 275250 bytes
-rw-r--r--demos/sqlmap/protected/pages/Manual/Tutorial/grid2.pngbin0 -> 218210 bytes
6 files changed, 568 insertions, 0 deletions
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 @@
+<com:TContent ID="body">
+<h1>Test, test, again ...</h1>
+<p>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.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+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);
+}
+</com:TTextHighlighter>
+
+<p>Not the best tests ever written, but for now, they will do :)</p>
+
+<p>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
+<tt>personHelper.xml</tt>.</p>
+
+<com:TTextHighlighter Language="xml" CssClass="source">
+<?xml version="1.0" encoding="utf-8" ?>
+
+<sqlMap Name="PersonHelper">
+ <select id="Select" parameterClass="int" resultClass="Person">
+ 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#
+ </select>
+
+ <insert id="Insert" parameterClass="Person">
+ 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#)
+ </insert>
+
+ <update id="Update" parameterClass="Person">
+ 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#
+ </update>
+
+ <delete id="Delete" parameterClass="int">
+ delete from PERSON
+ where PER_ID = #value#
+ </delete>
+</sqlMap>
+</com:TTextHighlighter>
+
+<p>Well, waddya know, if run our tests now, we are favored with a green bar!. It
+all works!</p>
+
+<div class="note"><b class="tip">Note:</b>
+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.
+</div>
+
+<p>Turning back to our Prado page, we can revamp the <tt>TDataGrid</tt> 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:TTextHighlighter Language="prado" CssClass="source">
+ &lt;com:TDataGrid id="personList"
+ DataKeyField="ID"
+ AutoGenerateColumns="False"
+ OnEditCommand="editPerson"
+ OnUpdateCommand="updatePerson"
+ OnCancelCommand="refreshList"
+ OnDeleteCommand="deletePerson">
+ &lt;com:TBoundColumn DataField="FirstName" HeaderText="First Name" />
+ &lt;com:TBoundColumn DataField="LastName" HeaderText="Last Name" />
+ &lt;com:TBoundColumn DataField="HeightInMeters" HeaderText="Height" />
+ &lt;com:TBoundColumn DataField="WeightInKilograms" HeaderText="Weight" />
+ &lt;com:TEditCommandColumn
+ HeaderText="Edit"
+ UpdateText="Save" />
+ &lt;com:TButtonColumn
+ HeaderText="Delete"
+ Text="Delete"
+ CommandName="delete"/>
+ &lt;/com:TDataGrid>
+ &lt;com:TButton Text="Add" OnClick="addNewPerson" />
+</com:TTextHighlighter>
+
+<p>The following sample shows the corresponding methods from page PHP class.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+ 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];
+ }
+</com:TTextHighlighter>
+
+<p>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.</p>
+
+<img src=<%~ grid2.png %> class="figure" />
+<div class="caption"><b>Figure 4:</b> Person List CRUD</div>
+
+</com:TContent> \ 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 @@
+<com:TContent ID="body">
+<h1>Test First!</h1>
+
+<p>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:</p>
+
+<p>"We would like to use a web application to display the people in this table
+and to add, edit, and delete individual records."</p>
+
+<p>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:</p>
+
+<com:TTextHighlighter Language="sql" CssClass="source">
+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
+</com:TTextHighlighter>
+
+<div class="tip"><b class="tip">Tip:</b>
+ This example is bundled with a SQLite database file "Data/test.db"
+ that contains the <tt>Person</tt> table and some data, ready to use.
+</div>
+
+<p>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.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+&lt;?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");
+ }
+}
+?&gt;
+</com:TTextHighlighter>
+
+<p>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?</p>
+
+<div class="note"><b class="tip">Note:</b>
+ Save the <tt>PersonTest.php</tt> into a <tt>tests</tt> directory.
+ The unit tests are written for the <a href="http://simpletest.sf.net">SimpleTest Unit Testing framework</a>.
+</div>
+
+<p>Now, to setup the testing framework, suppose you have the <tt>SimpleTest</tt>
+framework installed. Then we need to create an entry file to run the tests.
+See the <tt>SimpleTest</tt> documentation for further details on setting up tests.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+&lt;?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());
+?&gt;
+</com:TTextHighlighter>
+
+<p>To run the tests, point your browser to the "<tt>run_test.php</tt>" script file
+served from your web server.</p>
+
+<p>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</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+&lt;?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;
+ }
+}
+?&gt;
+</com:TTextHighlighter>
+
+<p>OK, that was fun! The <tt>$this->assertXXX(...)</tt> methods are built into
+<tt>UnitTestCase</tt> class. So to run the unit test example, we just need the
+<tt>TMapper</tt> object and <tt>queryForList</tt> method. Wonderfully, the SQLMap
+DataMapper framework has a <tt>TMapper</tt>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.</p>
+
+<p>When the <tt>TMapper-&gt;instance()</tt> method is called, an instance of the SQLMap
+<tt>TSqlMapper</tt> class is returned that has various methods available such as
+<tt>queryForList</tt>. In this example, the SQLMap <tt>TSqlMapper-&gt;queryForList()</tt>
+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
+<tt>queryForList()</tt>, there are also <tt>delete()</tt>, <tt>insert()</tt>,
+<tt>queryForObject()</tt>, <tt>queryForPagedList()</tt> and a few other methods in the
+<a href="?page=Manual.DataMapperAPI">SQLMap API</a>.
+
+<p>Looking at unit test example, we see that the <tt>queryForList()</tt> 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.
+
+<com:TTextHighlighter Language="xml" CssClass="source">
+<?xml version="1.0" encoding="utf-8" ?>
+<sqlMap>
+ <select id="SelectAll" resultClass="Person">
+ 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
+ </select>
+</sqlMap>
+</com:TTextHighlighter>
+
+<p>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.</p>
+
+<p>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?</p>
+
+<p>Surprise! More XML! You can define a configuration file for each datasource
+your application uses. The following code shows a configuration file named "<tt>sqlmap.config</tt>" for
+our SQLite database.</p>
+
+<com:TTextHighlighter Language="xml" CssClass="source">
+<?xml version="1.0" encoding="UTF-8" ?>
+<sqlMapConfig>
+ <provider class="TAdodbProvider">
+ <datasource driver="sqlite" host="Data/test.db" />
+ </provider>
+ <sqlMaps>
+ <sqlMap resource="Data/person.xml"/>
+ </sqlMaps>
+</sqlMapConfig>
+</com:TTextHighlighter>
+
+<p>The <tt>&lt;provider&gt;</tt> specifies the database provider class, in this case
+<tt>TAdodbProvider</tt> using the Adodb library. The <tt>&lt;datasource&gt;</tt> 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.</p>
+
+<p>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.</p>
+
+<p>OK, so how does the configuration get parsed?</p>
+
+<p>Look back at the unit test case example. The heart of the code is the call to the
+"<tt>TMapper</tt>" object (under the remark "try it"). The <tt>TMapper</tt> object
+is a singleton that handles the instantiation and configuration of an SQLMap
+<tt>TSqlMapper</tt> object, which provides a facade to the SQLMap DataMapper
+framework API.</p>
+
+<p>The first time that the <tt>TMapper</tt> is called, it reads in the
+<tt>sqlmap.config</tt> file and associated mapping documents to create an instance
+of the <tt>TSqlMapper</tt> class. On subsequent calls, it reuses the
+<tt>TSqlMapper</tt> object so that the configuration is not re-read.</p>
+
+<p>The framework comes bundled with a default <tt>TMapper</tt> class for you to use
+immediately to get access to the SQLMap client <tt>TSqlMapper</tt> object. If you want to use a
+different name other than <tt>sqlmap.config</tt> 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.</p>
+
+<div class="tip"><b class="tip">Tip:</b>
+ You can also call <tt>TMapper::configure('/path/to/your/sqlmap.config')</tt>
+ to configure the <tt>TMapper</tt> for a specific configuration file.
+</div>
+
+<p>If we put this all together into a solution, we can "green bar" our test. At
+this point you should have the following files.</p>
+<com:TTextHighlighter Language="code" CssClass="source">
+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.
+</com:TTextHighlighter>
+
+<p>Run the tests by pointing your browser URL to the "<tt>run_tests.php</tt>" server
+file.</p>
+
+<img src=<%~ example1.png %> class="figure" />
+<div class="caption"><b>Figure 2:</b> Green Bar!</div>
+
+</com:TContent> \ 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 @@
+<com:TContent ID="body">
+
+<h1>Playtest second!</h1>
+<p>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.</p>
+
+<h2>SQLMap and Prado</h2>
+<p>To setup Prado, we need to create the follow files and directory structure
+under our <tt>example/WebView</tt> directory.</p>
+<com:TTextHighlighter Language="code" CssClass="source">
+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
+</com:TTextHighlighter>
+
+<p>The <tt>application.xml</tt> and <tt>assets</tt> directory are not necessary but we
+will make use of them later. The <tt>application.xml</tt> is used to define some
+directory aliases and override the data source definitions in the
+<tt>sqlmap.config</tt>. This is because SQLite database files are defined
+relatively, otherwise we don't need to override the data source definitions.
+The example <tt>application.xml</tt> is shown below, defining path aliases and override SQLite database
+location.</p>
+
+<com:TTextHighlighter Language="xml" CssClass="source">
+<?xml version="1.0" encoding="utf-8"?>
+<application id="SQLMap Example" Mode="Debug">
+ <paths>
+ <alias id="Example" path="../../" />
+ <using namespace="System.DataAccess.*" />
+ </paths>
+ <modules>
+ <module id="SQLMap" class="TSQLMap"
+ configFile="Example.sqlmap">
+ <!-- override sqlmap.config's database provider -->
+ <provider class="TAdodbProvider">
+ <datasource driver="sqlite" host="../Data/test.db" />
+ </provider>
+ </module>
+ </modules>
+</application>
+</com:TTextHighlighter>
+
+<p>The entry point to a Prado application in this example is <tt>index.php</tt>
+and generally contains the following code.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+&lt;?php
+error_reporting(E_ALL);
+require_once('/path/to/prado/framework/prado.php');
+$application=new TApplication;
+$application->run();
+?>
+</com:TTextHighlighter>
+
+<p>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 <tt>TDataGrid</tt>. We save the file as <tt>Home.page</tt>.</p>
+
+<com:TTextHighlighter Language="prado" CssClass="source">
+<!doctype html public "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<head>
+ <title>Person</title>
+</head>
+<body>
+&lt;com:TForm>
+ <h1>Person List</h1>
+ &lt;com:TDataGrid id="personList">
+ &lt;com:TBoundColumn DataField="BirthDate"
+ HeaderText="Birth Date"/>
+ &lt;/com:TDataGrid>
+&lt;/com:TForm>
+</body>
+</html>
+</com:TTextHighlighter>
+
+<p>Of course, we still need to populate that TDataGrid. The following code
+shows the PHP for <tt>Home.php</tt>. The operative method is <tt>loadData()</tt>.
+The rest is supporting code.</p>
+
+<com:TTextHighlighter Language="php" CssClass="source">
+&lt;?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();
+ }
+}
+?&gt;
+</com:TTextHighlighter>
+
+<p>If we run this now, we'll get a list like the one shown the figure below.</p>
+<img src=<%~ grid1.png %> class="figure" />
+<div class="caption"><b>Figure 3:</b> A quick-and-dirty Person List</div>
+
+</com:TContent> \ 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
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/example1.png
Binary files 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
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/grid1.png
Binary files 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
--- /dev/null
+++ b/demos/sqlmap/protected/pages/Manual/Tutorial/grid2.png
Binary files differ