<!--{{{-->
<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml' />
<!--}}}-->
Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

.wizard .notChanged {background:transparent;}
.wizard .changedLocally {background:#80ff80;}
.wizard .changedServer {background:#8080ff;}
.wizard .changedBoth {background:#ff8080;}
.wizard .notFound {background:#ffff80;}
.wizard .putToServer {background:#ff80ff;}
.wizard .gotFromServer {background:#80ffff;}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity=60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which need larger font sizes.
***/
/*{{{*/
body {font-size:0.8em;}
#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}
.subtitle {font-size:0.8em;}
.viewer table.listView {font-size:0.95em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
#displayArea {margin: 1em 1em 0em;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::EditToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser excludeLists'></span></div>
<!--}}}-->
To get started with this blank [[TiddlyWiki]], you'll need to modify the following tiddlers:
* [[SiteTitle]] & [[SiteSubtitle]]: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* [[MainMenu]]: The menu (usually on the left)
* [[DefaultTiddlers]]: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These [[InterfaceOptions]] for customising [[TiddlyWiki]] are saved in your browser

Your username for signing your edits. Write it as a [[WikiWord]] (eg [[JoeBloggs]])

<<option txtUserName>>
<<option chkSaveBackups>> [[SaveBackups]]
<<option chkAutoSave>> [[AutoSave]]
<<option chkRegExpSearch>> [[RegExpSearch]]
<<option chkCaseSensitiveSearch>> [[CaseSensitiveSearch]]
<<option chkAnimate>> [[EnableAnimations]]

----
Also see [[AdvancedOptions]]
<<importTiddlers>>
The basics are useful only for standard [[CRUD]] operations and data validation by type, and while this covers a huge portion of development for the representing objects, it leaves out business logic, extended validation, and the low-level nuts and bolts for getting the most out of the system (and avoiding sneaky gotchas).

In order to help out with those more advanced considerations, here are the following:

* [[Garbage Collection]]: Keeping resource utilization low.
* ''Events'': See [[Extension]].
* [[Exceptions]]: Hints for managing errors states from Torpor.
* [[Extension]]: Adding or tweaking functionality to base classes.
* [[Sessions]]: Considerations for web implementations.
* [[Typed Grids|TypedGrid]]: Advanced Extension using automatically defined named classes.

Previous: [[Examples]]
Next: [[Garbage Collection]] (or [[Appendix]])
Other PHP ORM abstractions similar to Torpor include:
* [[Doctrine|http://www.doctrine-project.org/]]
* [[Propel|http://propel.phpdb.org/]] (most similar)
* [[Qcodo|http://www.qcodo.com/]]
* [[WikiPedia list of PHP ORM|http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software#PHP]]
# Class / Interface References
** [[Column|Class: Column]]
** [[CriteriaBase|Class: CriteriaBase]]
*** [[Criteria|Class: Criteria]]
*** [[CriteriaSet|Class: CriteriaSet]]
** [[DataStore|Interface: DataStore]]
*** [[ANSISQLDataStore|Class: ANSISQLDataStore]]
*** [[MSSQLDataStore|Class: MSSQLDataStore]]
*** [[MySQLDataStore|Class: MySQLDataStore]]
*** [[OracleDataStore|Class: OracleDataStore]]
*** [[SQLiteDataStore|Class: SQLiteDataStore]]
** [[Grid|Class: Grid]]
*** [[DebugGrid|Class: DebugGrid]]
*** [[TypedGrid|Class: TypedGrid]]
** [[GridColumnCollection|Class: GridColumnCollection]]
** [[GridSet|Class: GridSet]]
** [[PersistableContainer|Class: PersistableContainer]]
** [[PersistenceCommand|Class: PersistenceCommand]]
** [[Torpor|Class: Torpor]]
** [[TorporCache|Interface: TorporCache]]
*** [[ThreadCache|Class: ThreadCache]]
*** [[TorporMemcache|Class: TorporMemcache]]
*** [[SessionCache|Class: SessionCache]]
# [[Document Revision|Revision]]
# [[Supported Persistence Engines]]
An acronym for the 4 main activities of any repository or persistence layer in dealing with a record:
*''C''reate
*''R''ead
*''U''pdate
*''D''elete
Background: #fff
Foreground: #000
PrimaryPale: #fc8
PrimaryLight: #f81
PrimaryMid: #b40
PrimaryDark: #410
SecondaryPale: #ffd
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
''Optional.'' At most one entry is allowed, and with a single required {{{class}}} attribute to specify the PHP class which implements the {{{TorporCache}}} interface (one of the few classes to sport a prefix due to the probability of clashing with other common generic names).  This may either be a self-closing tag:

<html><span style="font-family: monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">Cache</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#ff6060">&quot;TorporMemcache&quot;</font><font color="#5555CC">/&gt;</font><br>
</span></html>
Or contain {{{Parameter}}} entities used to pass named arguments to the {{{Cache}}} class instance:

<html><span style="font-family:monospace;"><font color="#5555CC">&lt;</font><font color="#5555CC">Cache</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#ff6060">&quot;TorporMemcache&quot;</font><font color="#5555CC">&gt;</font><br/>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#ff6060">&quot;server_192.168.0.100&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">value</font>=<font color="#ff6060">&quot;11211&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#ff6060">&quot;ttl&quot;</font><font color="#5555CC">&gt;</font>10800<font color="#5555CC">&lt;/Parameter&gt;</font><br>
<font color="#5555CC">&lt;/Cache&gt;</font></font></span></html>

The {{{name}}} attribute of {{{Parameter}}} entities is required, but the {{{value}}} may either be provided as an attribute or as the interior content between open and closing tags.  This holds true for this same generic {{{Parameter}}} entity wherever it's found.

There is no limit to the number of {{{Parameter}}} entities that can be used, nor restriction on the content of {{{name}}} or {{{value}}} as far as the XML concerned (so long as it fits well-formed constraints - some content may need to be wrapped in {{{<![CDATA[]]>}}} qualifiers).  The meaning of the parameters and their contents is up to the particular {{{Cache}}} class, and should be explained in the corresponding documentation (more information can also be found in the [[Extension]] documentation).

Up: [[Configuration]]
Previous: [[Repository|Config: Repository]]
Next: [[Repository|Config: Repository]] / [[DataStore|Config: DataStore]]
Like {{{Grids}}}, the {{{Columns}}} element only serves to contain individual {{{Column}}} entities.

{{{Column}}} entities are the data / field members of the owning {{{Grid}}}.  It also has more attributes than any other element in the entire document (though all but 2 are optional):
<html><font face="monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;PasswordColumn&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;PASSWORD&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">default</font>=<font color="#990000">&quot;&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;false&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;32&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Password&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">nullable</font>=<font color="#990000">&quot;false&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">precision</font>=<font color="#990000">&quot;0&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">readOnly</font>=<font color="#990000">&quot;false&quot;</font><br>
<font color="#5555CC">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><br>
<font color="#5555CC">/&gt;</font></font></html>

Not all of these apply in every situation ({{{precision}}} has no bearing on non-numeric {{{type}}} values, for instance), but there's no harm in providing them in those cases - they will simply be ignored.  {{{Column}}} elements contain no other entities and no simple content (as contained between opening and closing tags).  Only the attributes matter, and their definition is as follows:

!!{{{dataName}}} and {{{name}}}
These follow the same conventions described for {{{//Grid@dataName}}} (see [[Grids|Config: Grids]]), both in construction and meaning to Torpor.

!!{{{class}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional'' (''required'' if {{{type}}} is set to "''class''")

This is the PHP class which should be instantiated for this {{{Column}}} when the containing {{{Grid}}} is created.  This will override all other class settings if provided, whether from a {{{DataTypeMap}}} or the overarching {{{ColumnClass}}}.  This must be a valid PHP class name or the special keyword "''none''" which opts the Column out of all {{{DataTypeMap}}} specifications, whereupon it will make use of the global {{{ColumnClass}}} definition.

!!{{{default}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional''

The contents of "default" will be the initial data value of this column upon instantiation.  Note that this //does// count as a data assignment event and the column //will// be marked as modified for publishing purposes.  This value will also be used if {{{reset()}}} is called on the column, rather than moving all the way to a null value (and will again be marked as having been modified in that state).

!!{{{encoding}}}
Default: ''(empty)''
Type: ''string''
Usage: ''optional''

This specifies the  encoding into which the contents of a string should be translated upon assignment in PHP.  
With no value set, no encoding translation will take place beyond PHP internal defaults, and strlen will be used for all length assessments.  If provided, the ''Multibyte String'' extension must be available to be useful (otherwise the value will be ignored, and an {{{E_USER_WARNING}}} generated), and this value must correspond to one of the values returned by {{{mb_list_encodings()}}}.  All incoming data will be subjected to {{{mb_convert_encoding()}}} to be explicitly set the internal encoding in order to be safe for use with the repository.  Note that in order to be used properly, some encoding types require that the locale be set prior to use and will affect the outcome of the conversion.

!!{{{generatedOnPublish}}}
Default: ''false''
Type: ''boolean''
Usage: ''optional''

Indicates late-binding data, potentially populated only once the record is published to the data store.  This special designation allows the repository adapter to populate the column value, and for Grid objects to associate with one another prior to publishing, maintain that association (this time with data) after publishing, and use it to trace dependencies to publish in a cascade fashion (assuming {{{PublishDependencies}}} is set to true).  It is still possible to manually populate this data as well.  This designation can be used for multiple columns in the same {{{Grid}}}, and columns of any data type.

!!{{{length}}}
Default: ''-1''
Type: ''integer'' (greater than or equal to ''-1'')
Usage: ''optional''

Values less than zero indicate "unlimited." zero-length strings are essentially useless and not recommended.  This attribute is enforced during assignment in PHP: data beyond this length will be truncated and an {{{E_USER_WARNING}}} will be generated.  If {{{encoding}}} is set and the ''Multibyte String'' extension is available, {{{mb_strlen()}}} is used to measure data length in number of characters; otherwise this will fall back to {{{strlen()}}}, which will almost certainly measure multi-byte strings in bytes instead of characters and may thus result in unintentional truncation for strings of sufficient length that are multi-byte encoding.

This attribute applies only to {{{binary}}}, {{{char}}}, {{{varchar}}}, and {{{text}}} type {{{Column}}} elements.

!!{{{nullable}}}
Default: ''true''
Type: ''boolean''
Usage: ''optional''

This indicates whether the {{{Column}}} may be assigned a literal PHP null.  Note that 0 (zero) or "" (empty string) do not count as null values during assignment.  Regardless of this setting, a newly instantiated Column object (or a linked column to another Column which has not yet been provided with its data) may contain null by virtue of not having yet been assigned.  In order to differentiate between a {{{nullable}}} {{{Column}}} which has not been assigned and one that has been assigned with a null value, the {{{Column::hasData()}}} method may be used.

!!{{{precision}}}
Default: ''0'' (zero)
Type: ''integer'' (signed)
Usage: ''optional''

This only has bearing on numeric {{{Column}}} types, and will simply be ignored in other contexts.  This refers to the number of decimal places OR the order of magnitude available to the data.  Order of magnitude is specified by making this negative (a precision of -2 for example will convert a number like ''12345'' to ''12300'' - with rounding at the point of truncation).  The default value is 0, so it is imperative that this be explicitly set for all floating point numeric data types.  {{{E_USER_WARNING}}} messages will be generated whenever truncation or loss of precision of incoming data occurs.

!!{{{type}}}
Default: ''(none)''
Type: ''enumeration'' (see below)
Usage: ''required''

This describes the data type as it will be represented within PHP.  It is possible, through the use of {{{Column::*PersistData}}} hooks, to support a disconnect between the repository data type and PHP data type.  Examples would include a database column of {{{CHAR(1)}}} or {{{INT}}} being used as a logical boolean, which can be treated within Torpor and PHP as a literal boolean but correctly filter/map back to the database conventions and limitations.  More on this can be found in the [[Extension]] documentation.

There are several different types allowed:
* ''binary:'' validates content byte length only, used to store raw data or file contents
* ''bool:'' literal boolean value, evaluates to/from true/false in PHP
* ''char:'' character/text data of variable encoding
* ''class:'' specifies that a different class will be used to represent this {{{Column}}}, sufficient to perform all necessary validation.  It is not required to have this value for any {{{Column}}} definitions with a {{{class}}} attribute defined. It should only be used when there is no need for extra type-hinted or controlled validation (including content length) outside of what the specified {{{class}}} will provide (which is a required attribute when this is set)
* ''date:'' stores date content in {{{YYYY-MM-DD}}} (PHP {{{date()}}} function argument {{{Y-m-d}}} is equivalent) format (where '-' may be omitted or any one of of {{{, . -}}} or {{{/}}} ).  Note that while structure will be validated, it is possible to specify out of range dates (such as February 31st) that may fail when it reaches the data store.  For full validation and useful utility methods it is highly recommended to wrap this in a {{{Column}}} extending class to expose/provide those features
* ''datetime:''' A concatenation of the {{{date}}} and {{{time}}} validations, separated by a single optional whitespace character
* ''float:'' floating point number, enforced as native {{{float}}} in PHP
* ''integer:'' signed integer number, enforced as native {{{int}}} in PHP
* ''text:'' character/text data of variable encoding, synonymous with char or varchar types
* ''time:'' 24-hour formatted time value with leading zeros, accepting {{{, :}}} or {{{-}}} as the separator: {{{HH:MI:SS}}} (PHP {{{date()}}} function argument {{{H:i:s}}} is equivalent).  Valid times are required, but beyond that there are no native utility operations for manipulating this value or translating it into other formats.  It is highly recommended to wrap this in an extending clss to expose/provide those features.
* ''unsigned:'' unsigned integer number, used as the native PHP {{{int}}} with the addition of the unsigned enforcement (greater than or equal to zero)
* ''varchar:'' character/text data of variable encoding, synonymous with char or text types


Up: [[Configuration]]
Previous: [[Grids|Config: Grids]]
Next: [[Grids|Config: Grids]] / [[Commands|Config: Commands]]
The {{{Commands}}} element is yet another simple plural-entity container that has no features or attributes in and of itself, and it is the {{{Command}}} that proves worthwhile.

All qualifying {{{Command}}} entries will be executed by the ~DataStore in the order in which they are defined based on {{{type}}}, and conditionally on {{{context}}}.  This is an operation of the native ~DataStore implementations, but not a hard rule - other extensions or custom classes may implement this differently.

''NOTE:'' this only applies to the generic {{{Delete}}}, {{{Load}}}, and {{{Publish}}} operations.  ~DataStore operations based on custom criteria and the like are still dynamically assembled.  In order to override that behavior individual [[PersistenceCommand|Class: PersistenceCommand]] objects or custom views should be used.

!Attributes
{{{Command}}} has 2 enclosed element types and 2 attributes, only 1 of which is required:
!!{{{type}}}
Default: ''(none)''
Type: ''enumeration: delete, load, publish''
Usage: ''required''

This tells the ~DataStore handler the operations this {{{Command}}} is intended to replace (future releases are planning to support an optional augmentation pattern rather than replacement, which will be backward compatible).  For each of these enumerations the corresponding ~DataStore will rely on this (or these) elements instead.  There may be an unlimited number of {{{delete}}} and {{{publish}}} operations, however only a single {{{load}}} element is supported.  This is enforced within the ~DataStore class rather than the XML, and while this is a limitation of the [[native DataStore handlers|Supported Persistence Engines]] it is not a constraint on their implementation per se - extensions or alternate handlers may work differently.

''NOTE:'' any command returning results are expected to do so according to the Torpor naming conventions for the populated {{{Columns}}}.  Even if the {{{dataName}}} is used, it will still need to be represented in the sanitized key version: {{{UserName}}} or {{{USER_NAME}}} both become {{{USERNAME}}} in this case.  See ''Examples'' below.

!!{{{context}}}
Default: ''(none)''
Type: ''enumeration: all, existing, new''
Usage: ''optional''

This differentiates between the ''Create'' and/or ''Update'' operations (of standard [[CRUD]] options) for any {{{Command}}} where {{{type="publish"}}}.  {{{new}}} applies only to ''Create'' activity, likewise {{{existing}}} applies only to ''Update'' operations, while ''all'' applies to both equally.  While technically optional, the native ~DataStore adapters examine this values to determine whether or not to include the {{{Command}}} in the list to execute.  An absent attribute will cause it to be omitted.  {{{context}}} is ignored when {{{type}}} is {{{delete}}} or {{{load}}}.

!Elements
!!{{{CommandText}}}
This contains the body of the {{{Command}}} to be executed by the ~DataStore as simple content, which in some cases may make sense to encapsulate as {{{<![CDATA[]]>}}}.  It also maintains 2 optional attributes:
!!!{{{placeholder}}}
Default: ''?''
Type: ''string''
Usage: ''optional''

The {{{placeholder}}} is the generic character found within the {{{CommandText}}} simple content that the ~DataStore will search for when making replacements or insertions based on unnamed {{{CommandParameter}}} elements.
!!!{{{type}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

Provided only for convenience, in case the ~DataStore needs to differentiate between invocation styles (SQL versus stored procedures, for example).  There are no pre-set values, and none of the native ~DataStore adapters use this - it is purely for convenience in extension.

!!{{{CommandParameter}}}
An optional, unlimited list of parameters to be combined with the {{{CommandText}}} via named (and/ordered) placeholders to compose the final command and/or its arguments.  This has no content in and of itself and should be treated as a self closing tag with 2 attributes:
!!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

The name of a {{{Column}}} (corresponding to either the {{{dataName}}} or {{{name}}} fo the {{{Column}}}, depending on which has been defined) which is to be the stand-in object (for bind variables) or the source of data (for simple parsing) when the {{{CommandText}}} is evaluated for execution.
!!!{{{placeholder}}}
Default: ''?''
Type: ''string''
Usage: ''optional''

If provided, this is the value which will be replaced (or the point at which the insertion will take place) by the specified {{{column}}} during preparation or execution.  If this is not distinct (such as is the case with the default ''?'' value) it will be inserted at the Nth placeholder corresponding to its order in the list.  If this //is// distinct, the insertion will take place at specifically that location without other qualification.  Note that the native ~DataStore adapters do simple pattern matching and expect but do not force word boundaries, thus is would be unwise to use {{{placeholder}}} values which are potentially sub-strings of other {{{CommandText}}} content.

!Examples
!!!~MySQL, simple order-based explicit placeholder {{{load}}} type
<html><font style="font-family: monospace;">
<font color="#5555CC">&lt;</font><font color="#5555CC">Command</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;load&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandText</font><font color="#5555CC">&nbsp;</font><font color="#009900">placeholder</font>=<font color="#990000">&quot;?&quot;</font><font color="#5555CC">&gt;</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;SELECT</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id AS USERID,</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name AS USERNAME,</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Password AS PASSWORD</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;FROM merged_user_view</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;WHERE Id = HEX( ? );</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#5555CC">&lt;/CommandText&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserID&quot;</font><font color="#5555CC">/&gt;</font><br>
<font color="#5555CC">&lt;/Command&gt;</font></font></html>

!!!~MySQL, simple order-based implicit placeholder {{{publish}}} type
<html><font style="font-family: monospace;">
<font color="#5555CC">&lt;</font><font color="#5555CC">Command</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;publish&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">context</font>=<font color="#990000">&quot;all&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandText</font><font color="#5555CC">&gt;</font><font color="#009900">&lt;![</font><font color="#CCCC00">CDATA</font><font color="#009900">[</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;REPLACE INTO users SET</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = HEX( ? ),</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp; = ?,</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Password = ?;</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">]]&gt;</font><font color="#5555CC">&lt;/CommandText&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Password&quot;</font><font color="#5555CC">/&gt;</font><br>
<font color="#5555CC">&lt;/Command&gt;</font></font></html>

!!!~MySQL, named placeholder {{{publish}}} type of restricted {{{context}}}
<html><font style="font-family: monospace;">
<font color="#5555CC">&lt;</font><font color="#5555CC">Command</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;public&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">context</font>=<font color="#990000">&quot;existing&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandText</font><font color="#5555CC">&gt;</font><font color="#009900">&lt;![</font><font color="#CCCC00">CDATA</font><font color="#009900">[</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;UPDATE users SET</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = HEX( :id ),</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Name&nbsp;&nbsp;&nbsp;&nbsp; = :name,</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Password = :password</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;ON DUPLICATE KEY UPDATE</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Id = Id + VALUE( Id );</font><br>
<font color="#990000">&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="#009900">]]&gt;</font><font color="#5555CC">&lt;/CommandText&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">placeholder</font>=<font color="#990000">&quot;:id&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">placeholder</font>=<font color="#990000">&quot;:name&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">CommandParameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Password&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">placeholder</font>=<font color="#990000">&quot;:password&quot;</font><font color="#5555CC">/&gt;</font><br>
<font color="#5555CC">&lt;/Command&gt;</font></font></html>

While these examples are ~MySQL specific (and not especially efficient in what they propose to do), they do at least serve to illustrate the utility of being able to specify custom structures and approaches to the ~DataStore internals for repository management, especially when one keeps in mind that multiple {{{delete}}} or {{{publish}}} entries may exist, chaining a series of commands together or acting as virtual triggers.  Stored procedure execution would follow a similar vein as outlined above.

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Columns|Config: Columns]]
Next: [[Grids|Config: Grids]] / [[DataTypeMap|Config: DataTypeMap]]
There are 2 possible sets of elements comprising the {{{DataStore}}} definition - either a single {{{DataStore}}} entry, or a pair of {{{ReadDataStore}}} and {{{WriteDataStore}}} elements similar in structure.  This allows for differentiated connection types, which is especially useful in master / slave replication setups.

The {{{type}}} attribute is required and technically unrestricted, though this is intended to correspond with one of the [[natively supported adapter|Supported Persistence Engines]] names:
* ~MySQL
* Oracle (or OCI)
* ~SQLite
* ~SQLServer (or MSSQL)
(as of the 1.0 release)

...or the special value "Custom", which should be used when a employing a user-defined ~DataStore class. The {{{class}}} attribute is optional unless {{{type}}} is set to "Custom" or any other non-native data store type.  If provided it will override the auto-detection used to map {{{type}}} to the corresponding Torpor ~DataStore class; essentially, {{{type}}} is a shortcut in describing native storage types so you don't have to remember or look up the corresponding class names (or files for inclusion).

No effort will be made to auto load non-native class files; if a Custom class has been requested, it had better exist or be made available via PHP's {{{__autoload}}}.

Interior to the actual {{{DataStore}}} element (regardless of {{{Read}}}, {{{Write}}}, or absent prefixes) are optional simple {{{name}}} / {{{value}}} pair {{{Parameter}}} entities to provide named arguments to the ~DataStore object instance.  The actual names and content of these entries are up to the ~DataStore class being used, and documentation can be found with each in turn (additional useful information can also be found in the [[Extension]] documentation).  {{{//DataStore/Parameter}}} entities (to use the ~XPath notation) feature an additional optional boolean attribute {{{encrypted}}}, which defaults to ''false''.  The intent is to indicate when the {{{value}}} of a {{{Parameter}}} is stored enciphered or otherwise obfuscated, requiring the ~DataStore class to extract the source value before it's actually useful.  This feature is not yet active in native Torpor classes, but is made available here in anticipation of future implementation and to be useful to any user extensions.

{{{DataStore}}} may either be a self-closing tag:

<html><font face="monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">DataStore</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;MySQL&quot;</font>/&gt;</font></font></html>

Or fully populated:

<html><font face="monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">ReadDataStore</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;MySQL&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;MySQLDataStore&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;host&quot;</font><font color="#5555CC">&gt;</font>localhost<font color="#5555CC">&lt;/Parameter&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;user&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">value</font>=<font color="#990000">&quot;testuser&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">encrypted</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;password&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">value</font>=<font color="#990000">&quot;ac56d8e742&quot;</font><font color="#5555CC">/&gt;</font><br>
<font color="#5555CC">&lt;/ReadDataStore&gt;</font></font>
</html>


Up: [[Configuration]]
Previous: [[Repository|Config: Repository]] / [[Cache|Config: Cache]]
Next: [[Grids|Config: Grids]]
The {{{DataTypeMap}}} entry is completely optional.  It may be used either as the last entity in [[Options|Config: Options]] where it will apply to every mapped Column type on every Grid, or it may be defined per-Grid or as the second-to-last member of the [[Grid|Config: Grids]] entity.  Its purpose is to instruct Torpor to instantiate every Column of a specific data type as a particular class.  This is especially useful for providing additional handlers, hooks (such as the {{{PersistData}}} hooks), validation, or other generally useful utility routines to particular data types (transparent encryption/decryption is a good example).

Whatever class name is provided here will be created as a new object using the PHP {{{new}}} keyword with the following arguments:
<html><span style="font-family: monospace;"><span style="color: #007700">new&nbsp;</span><span style="color: #0000BB">$class</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Torpor&nbsp;$torporInstance</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;(string)</span><span style="color: #0000BB">$columnName</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">SimpleXML</span><span style="color: #007700">&nbsp;</span><span style="color: #0000BB">$columnXml</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">Grid</span><span style="color: #007700">&nbsp;</span><span style="color: #0000BB">$grid<br /></span><span style="color: #007700">);</span></span></html>

The intent of these arguments and making changes generally are covered under [[Extension]] in [[Advanced Usage]].  It is generally recommended to inherit from {{{Column}}}, override just what's needed, and otherwise leave the constructor alone.

There are no defaults for {{{DataTypeMap}}} - those provided below are for illustration only.  Any type not appearing here will default to the value of the {{{ColumnClass}}} [[option|Config: Options]].

{{{DataMap}}} entries consist of a PHP class name and the Column data type to which that class name applies.  The same class name may appear multiple times, but only a single mapping per data type is supported.  If multiple are provided, only the last will be used.  The same class may be used multiple times without ill effects.

<html>
<span style="font-family: monospace;">
<font color="#5555CC">&lt;</font><font color="#5555CC">DataTypeMap</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">DataMap</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;DateTime&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;date&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">DataMap</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;DateTime&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;datetime&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">DataMap</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;DateTime&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;time&quot;</font><font color="#5555CC">/&gt;</font><br>
<font color="#5555CC">&lt;/DataTypeMap&gt;</font></span>
</html>

Up: [[Configuration]]
Previous: [[Options|Config: Options]]
Next: [[Repository|Config: Repository]] or [[Grids|Config: Grids]] / [[Keys|Config: Keys]]
The required {{{Grids}}} element's sole purpose is to contain one or more {{{Grid}}} entities.  It has no attributes or other options, and does not matter if there's only one {{{Grid}}}; this is where it goes.

Individual {{{Grid}}} entries are far more interesting:
<html><font face="monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;MyUserClass&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;USERS&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">readOnly</font>=<font color="#990000">&quot;false&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;data&quot;</font><font color="#5555CC">/&gt;</font></font></html>

Of course this isn't much use without [[Columns|Config: Columns]], and not every attribute is required, but this is where we start to get into the substance of the Torpor object factory.  Definitions and requirements of the attributes follow:
!!{{{dataName}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This is the only required attribute of {{{Grid}}}, used to identify the source of records of this Grid type to the ~DataStore engine.  This will also serve as the object type name in PHP unless {{{name}}} is also provided.

!!{{{class}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

A name of a PHP class that will overwrite the {{{GridClass}}} optional value for all instances of this grid, such that whenever new instances are created they will be manufactured as this type of object.  Note that this is not the same as {{{TypedGridClasses}}}, as this class name will not be automatically created by Torpor.  Nor is it required when using {{{TypedGridClasses}}} to place an entry here for every {{{Grid}}} corresponding to the grid-cum-class name, unless you want to override the automatically inferred class name.

!!{{{name}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

This is used to differentiate this {{{Grid}}} by something other than the {{{dataName}}} value.  It is recommended that this be a singular name, in order to avoid confusion in the API invocations.  If provided, this is the name by which it will be identified throughout the remainder of the configuration as well: any reference keys identifying this {{{Grid}}} need to use this value.  The Torpor style key, derived from either this or {{{dataName}}}, must be unique among all grids.

Eample: a recommended {{{name}}} value for a {{{Grid}}} with a name like {{{USER_ACCOUNTS}}} would be along the lines of {{{UserAccount}}}, in order to make the instantiation more explicit:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user_account&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserAccount</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$all_accounts&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserAccountSet</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user_account&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUserAccount</span><span style="color: #007700">();&nbsp;</span><span style="color: #FF8000">//&nbsp;etc.<br />//&nbsp;vs.<br /></span><span style="color: #0000BB">$user_account&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserAccounts</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$all_accounts&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserAccountsSet</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user_account&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUserAccountsSet</span><span style="color: #007700">();&nbsp;</span><span style="color: #FF8000">//&nbsp;etc.</span></span></html>

Pluralities are very distracting generally.  The new {{{name}}} need not have anything to do with the {{{dataName}}} either - these may be completely differentiated.

!!{{{readOnly}}}
Default: ''false''
Type: ''boolean''
Usage: ''optional''

Indicates that this grid will only be populated by the ~DataStore (and only from {{{<Object>Set}}} operations), and will never be published; attempting to do so will result in an exception).

''This feature is not fully implemented, and is here as a placeholder for future development.''

!!{{{type}}}
Default: ''data''
Type: ''enumeration: data, map''
Usage: ''optional''

Describes whether this {{{Grid}}} will contain pertinent records in their own right, or whether it serves solely as the glue between other {{{Grids}}} in a one- or many- to-many relationships.  Valid values are ''data'' (individual records) or ''map''.  For a ''map'' type Grid, all columns must either comprise the {{{Primary}}} key and be used in some {{{Foreign}}} key definition, or have suitable default values  Only under these circumstances is it possible to automatically maintain the contents based on Torpor activity.

''This feature is not fully implemented, and is here as a placeholder for future development.''


Up: [[Configuration]]
Previous: [[Repository|Config: Repository]] / [[DataStore|Config: DataStore]]
Next: [[Grids|Config: Grids]] / [[Columns|Config: Columns]]
Keys are used to define how one {{{Grid}}} may relate to others and the repository.  The main {{{Keys}}} element is simply a container for each of the different individual key types that may defined, and has no options or attributes itself.  It is considered optional, but is highly recommended - a {{{Grid}}} without any {{{Keys}}} defined can only be retrieved by constructing Criteria for searching, and any object that is retrieved will not be able to update.

There are 3 different key types supported:
* [[Foreign|Config: Keys: Foreign]]
* [[Primary|Config: Keys: Primary]]
* [[Unique|Config: Keys: Unique]]

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[DataTypeMap|Config: DataTypeMap]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Foreign|Config: Keys: Foreign]]
The optional {{{Foreign}}} element has no attributes nor simple-content of its own, and serves only as a container for one or more {{{Key}}} elements here defined.

{{{Foreign}}} type {{{Key}}} entries determine how this {{{Grid}}} can relate to any others that have been defined.  This is done by listing one or more {{{Key}}} elements indicating what {{{Column}}} here refers to what {{{Column}}} on another {{{Grid}}}, and optionally in what context.

For a reference to be viable, all {{{Key}}} elements referring to a target {{{Grid}}} must fully satisfy a unique identification of that {{{Grid}}}.  This is the case when either the {{{Primary}}} definition is fully represented here, or at least one complete {{{Unique}}} key definition.  This includes multiple-column keys: if a referenced {{{Grid}}} has a multi-column {{{Primary}}} key definition, this {{{Grid}}} would require multiple {{{Foreign}}} type {{{Key}}} entries, one per {{{Column}}}, to satisfy the relationships.  Same goes for {{{Unique}}} keys.

Note that this is grouped by context as well: a multi-column reference to another {{{Grid}}} as a particular {{{referenceGridAlias}}} would require that all {{{Key}}} entries share the same {{{referenceGridAlias}}} value.

There is no simple-content (as enclosed between starting and ending tags), and only 4 possible attributes (2 of which are optional).  This should be treated as a self-closing tag.

!Attributes
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}} and indicates the starting point of the reference.

!!{{{referenceColumn}}}
Default: ''(none)''
Type: ''string''
Usage: ''optional''

This must match the {{{dataName}}} (or {{{name}}}, if defined) or a {{{Column}}} on the {{{Grid}}} to which this {{{Key}}} refers.  It is only optional when the source {{{Column}}} and target {{{Column}}} are identically named and so the rest of the relationship can be inferred.

!!{{{referenceGrid}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of the {{{Grid}}} to which this {{{Key}}} refers.

!!{{{referenceGridAlias}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

One of the more powerful features of Torpor, this allows the referenced {{{Grid}}} to adopt a named context for access.  This means that, for example, an {{{Order}}} object can have a reference key to {{{User}}} without qualification, in which case {{{$order->getUser();}}} will product a {{{User}}} object, and at the same time may also have a reference key to {{{User}}} with a {{{referenceGridAlias}}} value of {{{Seller}}}, in which case {{{$order->getSeller();}}} will //also// produce a {{{User}}} object though this time corresponding to the different key (the reciprocal {{{set}}} methods also work in this fashion).

!Examples

These 2 simple {{{Grid}}} definitions show simple relationship definitions, from ''credit'' to ''entity''.  Note that the ''~SourceID'' reference to ''entity.~EntityID'' does //not// include a {{{referenceGridAlias}}} attribute.  This means both that {{{$credit->getEntity();}}} will automatically use ''~SourceID'' to find the related ''entity'' record, and that {{{$credit->getSource();}}} will ''//not//'' work because there is no ''source'' type {{{Grid}}} referenced nor alias defined by which to find such an object.

<html><span style="font-family: monospace; white-space: nowrap;">
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;credit&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;CreditID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;SourceID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;RecipientID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Amount&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;float&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">precision</font>=<font color="#990000">&quot;2&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;DateDeposited&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;date&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Foreign</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;SourceID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;entity&quot;</font><font color="#5555CC">&nbsp;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceColumn</font>=<font color="#990000">&quot;EntityID&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;RecipientID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;entity&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGridAlias</font>=<font color="#990000">&quot;Recipient&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceColumn</font>=<font color="#990000">&quot;EntityID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Foreign&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;CreditID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
<font color="#5555CC">&lt;/Grid&gt;</font><br>
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;entity&quot;</font><font color="#5555CC">&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;EntityID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">precision</font>=<font color="#990000">&quot;10&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Name&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;50&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">nullable</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Description&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;text&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">nullable</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;65535&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;EntityID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
<font color="#5555CC">&lt;/Grid&gt;</font></span></html>

Automatically available operations from this relationship:

<html><span style="color: #000000; font-family: monospace;">
<span style="color: #0000BB">$entity&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$credit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getEntity</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$entity&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$credit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRecipient</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$entity&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$credit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newEntity</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$entity&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$credit</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newRecipient</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$credit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$entity</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newCredit</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$credit&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$entity</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newCreditFromRecipient</span><span style="color: #007700">();<br /><br/></span><span style="color: #0000BB">$creditSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$entity</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getCreditSet</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$creditSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$entity</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getCreditSetFromRecipient</span><span style="color: #007700">();</span></span></html>



Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Primary|Config: Keys: Primary]]
The optional {{{Primary}}} element is a simple container with no attributes or simple-content of its own.  It's sole purpose is to hold {{{Key}}} elements which list the {{{Column}}} members of this {{{Grid}}} which comprise a unique identifier.  There is little difference in implementation between {{{Primary}}} and {{{Unique}}} key column lists, except that there may be at most 1 {{{Primary}}} element, and that the {{{Column}}}(s) so appearing here will be used in some short-cut and convenience functions elsewhere.  They also come into prominence for instantiating known TypedGrid objects.

''NOTE:'' No enforcement of the uniqueness of a {{{Primary}}} key is done within Torpor itself, and is solely the responsibility of the repository.  This definition is //logical//, not //practical//, and merely tells the framework that it may rely on this {{{Column}}} list in this fashion.

{{{Primary}}} type {{{Key}}} elements are almost as simple.  They contain no simple-content (as enclosed between start and end tags) and have only a single required attribute:
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}}.

And that's it.  Some simple {{{Grid}}} examples of single- and multiple- column key definitions include:

<html><span style="font-family: monospace">
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;account&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;AccountID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Name&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;50&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Type&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;8&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">default</font>=<font color="#990000">&quot;Checking&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Number&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;20&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Description&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;text&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;65535&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">nullable</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;AccountID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Name&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
<font color="#5555CC">&lt;/Grid&gt;</font><br>
<br>
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;account_balance&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;AccountID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">precision</font>=<font color="#990000">&quot;10&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Month&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;date&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Balance&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">precision</font>=<font color="#990000">&quot;10&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Foreign</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;AccountID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;account&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Foreign&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;AccountID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Month&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
<font color="#5555CC">&lt;/Grid&gt;</font></span></html>

Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Foreign|Config: Keys: Foreign]]
Next: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Unique|Config: Keys: Unique]]
The optional {{{Unique}}} elements are a simple container with no attributes or simple-content of its own.  It's sole purpose is to hold {{{Key}}} elements which list the {{{Column}}} members of this {{{Grid}}} which comprise a unique identifier.  There is little difference in implementation between {{{Primary}}} and {{{Unique}}} key column lists, except that there may be as many {{{Unique}}} elements as desired, and {{{Columns}}} may be repeated from one {{{Unique}}} list to the next.

''NOTE:'' No enforcement of the actual {{{Unique}}}-ness of a key is done within Torpor itself, and is solely the responsibility of the repository.  This definition is //logical//, not //practical//, and merely tells the framework that it may rely on a {{{Column}}} list in this fashion.

{{{Unique}}} type {{{Key}}} elements are vary simple.  They contain no simple-content (as enclosed between start and end tags) and have only a single required attribute:
!!{{{column}}}
Default: ''(none)''
Type: ''string''
Usage: ''required''

This must match the {{{dataName}}} (or {{{name}}}, if defined) of a {{{Column}}} on this {{{Grid}}}.

That's all there is to it.  Simple examples include:
<html>
<span style="font-family: monospace; white-space: nowrap;">
<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;user&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;integer&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;50&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Password&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;15&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;GUID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;64&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">encoding</font>=<font color="#990000">&quot;ISO-8859-1&quot;&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;ID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Password&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;GUID&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
<font color="#5555CC">&lt;/Grid&gt;</font></span></html>


Up: [[Configuration]]
Previous: [[Grids|Config: Grids]] / [[Keys|Config: Keys]] / [[Primary|Config: Keys: Primary]]
Next: [[Examples]]
Namespaces are a convention of XML used to group elements under a common name.  It is required to be a URI, but not necessarily required to correspond with any real or resolvable address.  The standard convention that has evolved out of convenience is to use a name which identifies the vendor or controller, and often a real location where information (or a schema) describing the format or its associated use can be found online.  Torpor is no exception, using a domain name the [[author|Paul Tomlinson]] had handy which links directly to the schema: http://www.tricornersoftware.com/Products/Torpor/Config/0.1

Within an XML document, this is linked to a namespace prefix by using a standard {{{xmlns}}} prefix as a qualifier (prefixes for prefixes is a little obscure, but a starting point needs to be established somewhere).  In the below example the new namespace declared associated with the URI above is the rather terse {{{trpr}}}; in reality this could be just about anything.  When this namespace prefix is affixed to an element name, it explicitly associates that element with the namespace and its definition.  In the case of the Torpor configuration schema, all of the member elements belong to the root {{{TorporConfig}}} element without any other namespaces or potential ambiguity of where an element might be defined.  Because of this, {{{trpr}}} (or whatever you use) need only be provided for the first element, after which everything else is implied:

<html>
<font face="monospace">
<font color="#5555CC">&lt;?</font><font color="#009900">xml</font><font color="#009900">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">&quot;1.0&quot;</font><font color="#5555CC">?&gt;</font><br>
<font color="#5555CC">&lt;</font><font color="#ff40ff">trpr</font><font color="#5555CC">:</font><font color="#5555CC">TorporConfig</font><font color="#5555CC">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">&quot;0.1&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">xmlns</font><font color="#5555CC">:</font><font color="#009900">trpr</font>=<font color="#990000">&quot;<a href="http://www.tricornersoftware.com/Products/Torpor/Config/0.1">http://www.tricornersoftware.com/Products/Torpor/Config/0.1</a>&quot;</font><font color="#5555CC">&gt;</font></font>
</html>

Because it's the root element it can define the {{{xmlns}}} to which it belongs at the same time it's invoking it.

The {{{version}}} attribute belongs to the {{{trpr}}} namespace in this example, and is a required attribute of {{{TorporConfig}}}.  It's used to tell Torpor what version of the configuration is in play in order to determine if it is compatible with the current installation and what feature set may be available.  Note that there is not a direct correlation between the Torpor release number and the configuration version number.

It's possible to explicitly declare the schema and its location (not just a namespace which happens to do the same, which doesn't really mean much to the interpreter) using additional XML conventions, but these aren't required unless standalone validation is being performed without explicitly specifying the schema against which the validation should be checked.  The [[repository extraction scripts|Repository Extraction]] scripts use this advanced output by default for convenience, but it doesn't change the standard approach or the schema location against which it is finally validated.

Up: [[Configuration]]
Next: [[Options|Config: Options]]
Located directly below the {{{<TorporConfig>}}} opening element, {{{Options}}} is one of the  few elements out-of-place with regard to it's order in the alphabet (almost all elements are provided in their alphabetical order for convenience, and will be enforced as such by the schema - deviations from this standard will be noted where they occur).  This is for convenience in editing, since it contains global configuration values that in many ways will dictate the nature of other content in the document.  Putting it in a logical order, easily located at the top of the document, makes a certain amount of sense from this perspective.  Under {{{Options}}}, individual settings are provided using simple-content XML entities where the value is placed between opening and closing tags with no attributes: <html><span style="font-family: monospace; white-space: nowrap;">
<span style="color:#55C;">&lt;SampleSetting&gt;</span>value<span style="color:#55C;">&lt;/SampleSetting&gt;</font></span></html>

These are ordered alphabetically with the next exception of [[DataTypeMap|Config: DataTypeMap]], which is placed at the end of the list so as to avoid visual clutter in editing since it does not follow the simple-content entity standard of all the others.  The {{{Options}}} XML entity output by the [[repository extraction scripts|Repository Extraction]] is a self closing tag ({{{<Options/>}}}) with no values, indicating that defaults will be used for all settings.

!!{{{CacheReferencedGrids}}}
Default: ''true''
Type: ''boolean''

If set to true, when one Grid is used as the source for fetching another related Grid, the source Grid will cache a reference in that context (meaning using any alias name under which the related Grid is fetched) to the resulting object.  This means that not only will repeated calls produce the same Grid record, they will produce it as represented by the the same object reference.  This is a performance enhancement which allows for useful repeat call patterns such as:

<html><span style="font-family: monospace;"><span style="color: #007700">if(&nbsp;</span><span style="color: #0000BB">$someGrid</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRelatedRecord</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Load</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">doSomethingTo</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$someGrid</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRelatedRecord</span><span style="color: #007700">()&nbsp;);<br />}</span></span></html>

Note that it is possible for a single record from the repository to be represented by multiple different object instances, and even in different states as making alteration to one does not propagate to the other.  This behavior is intentional, but comes with a caution of being sure you know what you're doing if you really want more than one.  The {{{PublishAllColumns}}} setting outline below can act as a partial safeguard in these situations as well.

!!{{{CacheReferencedGridSets}}}
Default: ''false''
Type: ''boolean''

Similar in purpose to {{{CacheReferencedGrids}}}, this determines whether or not to do the same with ~GridSet objects.  This is off by default, as the relationship between a Grid and resulting ~GridSet is less tightly coupled than from one Grid to another (examples of the loose coupling include differing Criteria, pagination, or otherwise restricted or qualified sub-set of records that may not always be the intent).

!!{{{ColumnClass}}}
Default: ''Column''
Type: ''string''

This is the PHP class name which will be used as the base prototype for every Grid's Column (unless overridden by [[DataTypeMap|Config: DataTypeMap]] or [[Column|Config: Columns]] settings), and must correspond to a legitimate class name (preferably something which extends Column).

!!{{{Debug}}}
Default: ''false''
Type: ''boolean''

May cause more {{{E_USER_NOTICE}}} events to be produced.  Debug //classes// are a wiser choice, allowing more granularly targeted hooks under user control.

!!{{{GridClass}}}
Default: ''Grid''
Type: ''string''

PHP class name for all Grid prototypes unless overridden per-[[Grid|Config: Grids]] later on.

!!{{{LinkUnpublishedReferenceColumns}}}
Default: ''true''
Type: ''boolean''

This rather long-named option controls whether or not, when using a Grid as a factory for a related Grid, or associating two Grids in a specific context, whether or not to automatically link the corresponding reference Columns between the two in situations where:
# A referenced Column does not currently have data
# That Column has {{{generatedOnPublish}}} set to ''true''
This allows Grid types which have late-binding keys established by the repository to still be associated to one another without having to summarily publish everything just to get that key.  Once established, any request to the source Column for data will be redirected to the now linked target Column to retrieve it's data (if it has any), which will then be stored locally (with the source Column) and finally returned to the calling interface.

Such a pattern allows objects with repository-generated-keys to be associated with one another prior to publishing, which in turn improves performance and prevents partial records from being written to the repository for the sole purpose of generating keys or making some other key-determining round trip (e.g., fetch from a sequence) for resources which may not even be used if the objects are never published.

This has bearing on {{{PublishDependencies}}}: these are the dependencies it's referring to.  If a linked Column is encountered with no data of its own, and the target of that link is {{{generatedOnPublish}}}, that target will be published first and the resulting key propagated to the requesting object. See {{{PerpetuateAutoLinks}}} too.

!!{{{OverwriteOnLoad}}}
Default: ''true''
Type: ''boolean''

Determines when loading an object from the repository whether to overwite any data which was set on the object prior to that fetch or prior to the Grid's ability to load.  When true, any data already set (which does not correspond to the loaded data) will be wiped out.  This will also generate an {{{E_USER_NOTICE}}} warning to indicate somebody's data is going missing, in case this results in aberrant or unexpected behavior.

!!{{{PageSize}}}
Default: ''-1''
Type: ''integer'' (greater than or equal to ''-1'')

The number of records to fetch from the repository for ~GridSet type objects where the local {{{GridSet::setPageSize()}}} has not been explicitly set.  A negative number corresponds to "all available records," and is not recommended (especially for web apps) unless you really need all records.  However, this is the default in order to avoid nasty surprises in the form of failing to operate on all records matching requested criteria.

!!{{{PermitDDL}}}
Default: ''false''
Type: ''boolean''

Whether or not any data description language (modifications to repository structure) will be permitted.  Disabled by default, and probably only useful if one plans on working with temporary tables and the like.  Whether or not something is DDL is up to the repository handler to figure out, and for that handler to query this setting - it is not pushed to the handler, nor does anything else introspect incoming queries.  General behavior when set to ''false'' is to throw an [[exception|Exceptions]] when DDL is encountered.

!!{{{PerpetuateAutoLinks}}}
Default: ''false''
Type: ''boolean''

Used together with {{{LinkUnpublishedReferenceColumns}}}, this setting indicates whether or not to maintain that linked relationship after data has been retrieved from the target Column.  When set to false, as soon as some data has been retrieved from the target Column the link will be severed and the 2 will go their separate ways.  This is the default, since reference keys between records are not expected to change with sufficient frequency to warrant continuing the link.  If set to true, however, the 2 objects will continue to operate in tandem; useful if keys are expected to be changing for some reason.

''NOTE:'' The source Column data is not pushed to by the target Column; the link relationship is one strictly of pull to source from target when the source Column's data is requested.  Thus it's possible to change the target Column's data many times before the source Column ever wises up.  Just FYI.

!!{{{PublishAllColumns}}}
Default: ''false''
Type: ''boolean''

Determines whether or not to publish all Columns, or just those which have changed since it was loaded.  Applies to loaded Grids only (since all newly created records will be published in their entirety anyway), and is not recommended as ''false'' for use with distributed caching unless {{{ReloadAfterPublish}}} is also ''true'', since the Cache interface is "all or nothing" rather than a delta set.  This feature helps optimize repository performance and can assist in reducing incidental data overwrites at the final repository level in the event that multiple references to the same record are in play at the same time.

If only a few values are changing on a larger Grid object, and especially if this happens with any frequency, there will be a decrease in overall network traffic and database load.  This is most useful in for repositories (or their ~DatatStore adapters) which do not support pre-compiled queries and bind variables for performance,  since it does require that custom queries be assembled and parsed each time which negate any pre-compilation performance gain.  

!!{{{PublishDependencies}}}
Default: ''true''
Type: ''boolean''

If a required Column does not have data, and is linked to a Column which also does not have data but is set to generatedOnPublish, this setting determines whether to publish the linked target Column in order to retrieve its data for use in the source Column we're intending to publish which requires it.  This is a recursive-safe operation in that it will detect circular references, but only in that it will detect them - it will throw an exception rather than segfaulting, and it's up to the calling code to determine how to handle the error.

!!{{{ReloadAfterPublish}}}
Default: ''true''
Type: ''boolean''

Once a Grid has been published, this setting determines whether to mark the Grid as not yet having loaded, such that subsequent requests for data will cause the standard just-in-time load to fire.  Though this slightly decreases performance (by increasing repository communication), it's useful in those circumstances where data may have been altered once it hit the repository (precision truncation, formatting, etc.) in order to ensure everything stays in agreement.  If set to ''false'',however, the data as constituted in that Grid at the moment of publish will persist, both locally and in any Cache configuration.  It is recommended to test the Column data type handling as it corresponds to resulting publish operations in the database to ensure that, in whatever environment you're using things, it all lines up before setting this to ''false'' (which can result in a significant decrease in database load).

''NOTE:'' This has no bearing on {{{generatedOnPublish}}} columns, which will //always// be populated from the repository as a part of the whole publish operation.

!!{{{TypedGridClasses}}}
Default: ''false''
Type: ''boolean''

If set to true, instead of using Torpor's {{{Grid}}} class for all record instances, a new class will be created as an extension to the class {{{TypedGrid}}}.  The new class name will correspond to the sanitized Torpor key name for the Grid (e.g., {{{User}}} becomes {{{USER}}}, {{{order_item}}} becomes {{{ORDERITEM}}}, etc.) - due to PHP case handling these can still be accessed case insensitively for convenience ({{{User}}}, {{{OrderItem}}})

This is most useful in a singleton environment, but can also be used with Torpor as an instance if that instance is passed as an argument in the construction of the object: <html><span style="font-family: monospace;"><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">User</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$torpor&nbsp;</span><span style="color: #007700">);</span></span></html>

''NOTE:'' Torpor must either already have been initialized from the configuration file, or be used with appropriate hooks in the lazy loader ({{{__autoload}}} function) in order for this pattern to be used. See also {{{TypedGridClassesPrefix}}} and [[TypedGrids|TypedGrid]].

!!{{{TypedGridClassesPrefix}}}
Default: ''(empty)''
Type: ''string''

Empty by default, any string used here will be prefixed to the class names constructed when {{{TypedGridClasses}}} is ''true''.  For example, if this contained {{{Torpor}}} and a Grid {{{User}}} was defined, the new class would be named {{{TorporUser}}} (technically {{{TorporUSER}}} due to the key sanitation, but for readability Pascal case is used - class names are thankfully case insensitive in PHP).


Up: [[Configuration]]
Previous: [[Namespace|Config: Namespace]]
Next: [[Options|Config: Options]] / [[DataTypeMap|Config: DataTypeMap]]
The {{{Repository}}} element has no attributes or extra values itself, instead serving only as a functional container for the [[Cache|Config: Cache]] and [[DataStore|Config: DataStore]] definitions.

Up: [[Configuration]]
Previous: [[Options|Config: Options]] / [[DataTypeMap|Config: DataTypeMap]]
Next: [[Repository|Config: Repository]] / [[Cache|Config: Cache]]
All configuration files are validated against the {{{TorporConfig.xsd}}} schema to ensure valid structure and content.  If you are unfamiliar with schema validation or XML nuances in general I recommend the excellent [[ZVON.org|http://www.zvon.org/]] resources and tutorials.  If you follow then conventions outlined in this guide you should be just fine regardless.

The smallest successfully validating example is not especially useful:
<html>
<font face="monospace">
<font color="#5555CC">&lt;?</font><font color="#009900">xml</font><font color="#009900">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">&quot;1.0&quot;</font><font color="#5555CC">?&gt;</font><br>
<font color="#5555CC">&lt;</font><font color="#ff40ff">trpr</font><font color="#5555CC">:</font><font color="#5555CC">TorporConfig</font><font color="#5555CC">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">&quot;0.1&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">xmlns</font><font color="#5555CC">:</font><font color="#009900">trpr</font>=<font color="#990000">&quot;<a href="http://www.tricornersoftware.com/Products/Torpor/Config/0.1">http://www.tricornersoftware.com/Products/Torpor/Config/0.1</a>&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Grids</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;Example&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Grids&gt;</font><br>
<font color="#5555CC">&lt;/</font><font color="#ff40ff">trpr</font><font color="#5555CC">:</font><font color="#5555CC">TorporConfig&gt;</font><br>
</font>
</html>
This is still allowed to pass because the majority of the configuration values are optional.  The above example will allow Torpor to act as a factory for an {{{Example}}} pseudo-class that has no column members, and will not be able to load or publish because there's no [[repository|Config: Repository]] defined (but then, there's no data to load or publish either so that's hardly consequential).

Any option or setting omitted from the XML will use a default setting instead.  These are defined in the schema for those using it to assist in the generation of the configuration file (or to act as a near-at-hand reference and correspond to the default values in the {{{Torpor}}} class.  There is also an included {{{TorporConfig.sample.xml}}} file annotated with the same content found here using inline {{{<!-- XML comments -->}}}.

By default a new {{{Torpor}}} instance (singleton or otherwise) will attempt a just-in-time initialization the first time it's asked to do something that requires an internal data structure.  It will look in the PHP include path for a file name {{{TorporConfig.xml}}}, stopping at the first one it finds, and use that as the basis of operation.  This behavior can be overridden by setting a {{{TORPOR_CONFIG}}} environment variable (containing a file name, URI, or even XML content), or calling the {{{Torpor::initialize()}}} method with an argument specifying the desired XML contents as a string, the name of the configuration file, a file handle, ~SimpleXML instance, or URI.  Regardless of how the XML gets there, it all needs to follow the same rules.

# [[Namespace|Config: Namespace]]
# [[Options|Config: Options]]
## [[DataTypeMap|Config: DataTypeMap]]
# [[Repository|Config: Repository]]
## [[Cache|Config: Cache]]
## [[DataStore|Config: DataStore]]
# [[Grids|Config: Grids]]
## [[Columns|Config: Columns]]
## [[Commands|Config: Commands]]
## [[DataTypeMap|Config: DataTypeMap]]
## [[Keys|Config: Keys]]
### [[Foreign|Config: Keys: Foreign]]
### [[Primary|Config: Keys: Primary]]
### [[Unique|Config: Keys: Unique]]

Previous: [[Getting Started|Getting Started with Torpor]]
Next: [[Namespace|Config: Namespace]] (or [[Examples]])
[[Introduction]]
Distribution packages are maintained via the [[Torpor Project Page|http://code.google.com/p/torpor-php/]] on [[Google Code|http://code.google.com]]:
* http://code.google.com/p/torpor-php/downloads/list
The examples in this section will be done using an explicit instance of Torpor as the basis of all operations.  In the [[Advanced Usage]] section the possibility of object instantiation without this is discussed; though it might simplify the examples to use a similar syntax here, the initial configuration and the caveats surrounding TypedGrid use warrant separate consideration and treatment.  The initialization and instantiation of Torpor in the context shown here is simpler and safer, and so will act as the foundation for these examples.

All these examples assume that one of the following has taken place:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$MyTorpor&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">::</span><span style="color: #0000BB">getInstance</span><span style="color: #007700">();</span><br/>
<span style="color: #0000BB">$MyTorpor&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">();</span></span></html>

...and that it has been initialized using [[simple_sample.xml]] (with a corresponding database available):

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">initialize</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'simple_sample.xml'&nbsp;</span><span style="color: #007700">);</span></span></html>

!!A Note About Keywords
Torpor operations are composed of keywords and modifiers which identify what one is attempting to do, what it's being done to, and the context or manner in which that should be done. This follows a simple syntax such as:
{{{
<verb><ObjectType>[Set][From<ObjectType>]
}}}

Where {{{<verb>}}} can be any of:
* {{{add}}}
* {{{can}}}*
* {{{get}}}
* {{{is}}}*
* {{{map}}}*
* {{{new}}}
* {{{set}}}
({{{can}}} and {{{is}}}, and {{{map}}} don't follow the full syntactical expansion described above and have their own use cases explored elsewhere).

It is recommended to avoid using keywords in object names solely for the purpose of avoiding confusion; the intended operations can still be performed on the target objects successfully, but only by repeating the keywords in the appropriate places which may make some code less readable.  It's also recommended because while Torpor primitives can assure this kind of correct operation, developer or third-party extensions may not provide the same guarantee.

!!Examples:
# [[The Basics|Examples: Basics]]
# [[Related Objects|Examples: Related Objects]]
# [[Collections and Criteria|Examples: Collections and Criteria]]

Previous: [[Configuration]]
Next: [[The Basics|Examples: Basics]]
All Torpor operations are based on a simple vocabulary that identifies an action, the object(s) on which to perform the action, and any related object to use in that operation.  This applies to both to {{{Grid}}} objects and any {{{Column}}} members.

!!Your First Object
<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();</span></span></html>

The keyword {{{new}}} is followed by the name of an object type.  This name must correspond to either the {{{name}}} or {{{dataName}}} of a [[Grid|Config: Grids]] entry in the configuration.  While the name must be composed of alphabetic characters only, it's also completely case insensitive, and agnostic to the placement of underscores (which are frequently used in database naming conventions).

Each {{{Grid}}} object has the same basic operations for retrieving, saving, and deleting data:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Load</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Publish</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Delete</span><span style="color: #007700">();</span></span></html>

Of these, {{{Publish}}} and {{{Delete}}} are going to be the most useful in terms of implementing code.  The {{{Load}}} operation happens implicitly whenever {{{get}}} is called on any of the member Columns, the object is capable of loading (meaning either the primary key or one or more unique keys have all member columns populated with data), and has not yet been loaded.  {{{Publish}}} predictably stores the object in the repository, {{{Delete}}} removes it (and empties all data out of the object instance), and {{{Load}}} retrieves it based on the identifying criteria inherent in its definition.   The full definition of these methods, their arguments and operations, can be found in the API reference in the [[Appendix]] under ''Class References / [[Grid|Class: Grid]]''.

!!Member Variables
Once we have our object, operating on its data members is easy.  This is a new instance without any default values, so let's try some {{{set}}} operations first:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setUserName</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'harry'&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setEmail</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'harry@example.com'&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setPasswordHash</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'12345'&nbsp;</span><span style="color: #007700">)&nbsp;);</span></span></html>

We can then retrieve those values using {{{get}}} operations; this time exercising the case insensitivity just for fun:

<html><span style="font-family: monospace;">
<span style="color: #007700">print&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUSER_NAME</span><span style="color: #007700">();<br />print&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">get_email</span><span style="color: #007700">();<br />print&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">GET_PASSWORD_HASH</span><span style="color: #007700">();</span></span></html>

It's also possible to use direct object member access syntax to do the same things:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">UserName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'harry'</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Email&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">UserName</span><span style="color: #007700">.</span><span style="color: #DD0000">'@xample.com'</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">PasswordHash&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'12345'&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">print_r</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;array(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">USER_NAME</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">EMAIL</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">pAsSwOrD_HaSh<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />);</span></span></html>

Again, completely case insensitive and underscore agnostic.  This is because PHP's magic {{{__get}}} and {{{__set}}} functions have been overridden, just as {{{__call}}} has, in order to introspect the request and determine the intended operation.  This even allows for increment and decrement operations and inclusive assignment:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">ID&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">54321</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">ID</span><span style="color: #007700">++;<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">ID</span><span style="color: #007700">--;<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">ID&nbsp;</span><span style="color: #007700">%=&nbsp;</span><span style="color: #0000BB">4</span><span style="color: #007700">;</span></span></html>

There are 2 special extensions to the standard access patterns for {{{Column}}} objects of type {{{boolean}}}.  Assuming that we extended {{{User}}} to include a boolean member variable {{{Active}}}, it would be possible to do the following:

<html><span style="font-family: monospace;">
<span style="color: #007700">if(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">IsActive</span><span style="color: #007700">()&nbsp;){&nbsp;</span><span style="color: #FF8000">/*...*/&nbsp;</span><span style="color: #007700">}<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setActive</span><span style="color: #007700">();</span></span></html>

Where the {{{is<ColumnName>()}}} returns the {{{boolean}}} value of the {{{Column}}}, and the {{{set<ColumnName>()}}} method //with no arguments// (and this is critical, in case the italics didn't give it away) will default to {{{true}}}; a literal //null// or otherwise empty variable still counts as an argument and will be evaluated as a {{{boolean}}} in making the assignment.

!!Working with Column Objects
Any time one of the {{{get}}} or {{{set}}} operations is invoked, the Grid object (in this case {{{User}}}) determines the intended operation and its member Column object against which to apply that operation by calling the corresponding method no the Column itself.  Direct developer access to Column objects is also possible and encouraged.  This example shows the {{{Grid::hasColumn()}}} method, the {{{Grid::Column()}}} accessor, and the {{{array}}} style iterator interface, all working with Column objects directly ({{{$user->$columnName}}} is technically a simple {{{get}}} accessor, but fits well with the example).  Note that the Column object also supports the {{{__toString()}}} magical method, implicitly calling {{{getData()}}} to provide the results:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$columnName&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'Id'</span><span style="color: #007700">;<br />if(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">hasColumn</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$columnName&nbsp;</span><span style="color: #007700">)&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">$columnName</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Column</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$columnName&nbsp;</span><span style="color: #007700">)-&gt;</span><span style="color: #0000BB">getData</span><span style="color: #007700">();<br />}<br /><br />foreach(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$columnName&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$columnObject&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #0000BB">$columnName</span><span style="color: #007700">.</span><span style="color: #DD0000">':&nbsp;'</span><span style="color: #007700">.</span><span style="color: #0000BB">$columnObject</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getData</span><span style="color: #007700">().</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #0000BB">$columnName</span><span style="color: #007700">.</span><span style="color: #DD0000">':&nbsp;'</span><span style="color: #007700">.</span><span style="color: #0000BB">$columnObject</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />}<span></span></html>

As a special feature, calling the Column name as a //method// of {{{Grid}}} will also return the underlying {{{Column}}} object:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$aColumn&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Id</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$aColumn&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">UserName</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$aColumn&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">();<span></span></html>

The same rules of case and underscore insensitivity apply.

The full list and definition of Column methods, their arguments and operations, can be found in the API reference in the [[Appendix]] under ''Class References / [[Column|Class: Column]]''.

!!Retrieving Content
Any {{{Grid}}} that has all member {{{Column}}}s of a key (either [[primary|Config: Keys: Primary]] or [[unique|Config: Keys: Unique]]) populated may be retrieved from the repository if a corresponding record exists.  As {{{User}}} has been defined, each of the ID, user name, and email address are considered distinct in their own right.  As a result, if any of these contain data, the full record may be loaded.  Assume we have the following records in the repository:
| !~USER_ID | !~REFERRING_USER_ID | !~USER_NAME | !~EMAIL_ADDRESS | !PASSWORD |h
| 123 | //null// | montreal | montreal@example.com | 5f4dcc3b5aa765d61d8327deb882cf99 |
| 456 | 123 | ottowa | ottowa@example.com | 5ebe2294ecd0e0f08eab7690d2a6ee69 |

The following code:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">456&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$otherUser&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$otherUser</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setEmail</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'montreal@example.com'&nbsp;</span><span style="color: #007700">);<br /><br />foreach(&nbsp;array(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$otherUser&nbsp;</span><span style="color: #007700">)&nbsp;as&nbsp;</span><span style="color: #0000BB">$userObj&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #DD0000">"USER\n----------\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;foreach(&nbsp;</span><span style="color: #0000BB">$userObj&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$columnName&nbsp;</span><span style="color: #007700">=&gt;&nbsp;</span><span style="color: #0000BB">$column&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #DD0000">"$columnName:&nbsp;$column\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;print&nbsp;</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />}</span></span></html>

...would produce the following output:
{{{
USER
----------
ID: 456
REFERRINGUSERID: 123
USERNAME: ottowa
EMAIL: ottowa@example.com
PASSWORDHASH: 5ebe2294ecd0e0f08eab7690d2a6ee69

USER
----------
ID: 123
REFERRINGUSERID: 
USERNAME: montreal
EMAIL: montreal@example.com
PASSWORDHASH: 5f4dcc3b5aa765d61d8327deb882cf99

}}}

Useful functions in this regard include {{{Grid::canLoad()}}} and {{{Grid::isLoaded()}}} which can be used to introspect the current state of the object.  Explicit loading can be done via {{{Grid::Load()}}}, which will only actually load an object once no matter how many time's it's called, unless it is forced to refresh by passing {{{true}}} to the {{{Load()}}} method.

!!Saving Content
Saving an object to the repository is the same whether it's a new object, or an existing one that has been changed:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />if(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">canPublish</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Publish</span><span style="color: #007700">();<br />}</span></span></html>

!!Deleting Content
Any object which returns {{{true}}} from {{{canLoad()}}} has enough identifying criteria to also delete any corresponding record in the repository:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />if(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">canPublish</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Delete</span><span style="color: #007700">();<br />}</span></span></html>

Once done, the {{{$user}}} object will be as empty as if newly created and the repository (and cache, if in use) will have been cleared of the identified record.

!!Errors
Any attempt to access a member variable which does not exist, in any context, will produce a {{{TorporException}}} (which is a simple extension to PHP's built-in {{{Exception}}}, to make containment easier).  This includes {{{get}}} and {{{set}}} operations, {{{Grid::Column()}}} retrieval, or the implicit {{{$user->Id()}}} "column name as method" syntax.  It's wise to have a default exception handler or wrap Torpor operations in {{{try { /*...*/ } catch( TorporException $e ){ /*...*/ } }}} blocks.  More on this can be found in the [[Exceptions]] section.

Up: [[Examples]]
Next: [[Related Objects|Examples: Related Objects]]
Collections in Torpor are referred to as a {{{Set}}}.  These are used to hold zero or more {{{Grid}}} objects of the same type, and may be populated either manually (by adding each one in turn), by retrieving a series of records from the repository, or both.  It supports just-in-time loading using efficient bulk-load operations, and the standard iterator interface for use in {{{foreach}}} loops, and the same advanced relationship operations as individual {{{Grid}}} objects.

!Instantiation
A {{{GridSet}}} (or {{{TypedGridSet}}}, as the case may be) can either be instantiated directly, or through corresponding [[related object|Examples: Related Objects]] factory methods.  The following 2 approaches accomplish exactly the same thing: create a new {{{Order}}} type {{{GridSet}}} object associated with {{{$user}}}.

<html><span style="color: #000000"><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">12345&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderSet</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrderSet</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);</span></span></html>

The use of the {{{set<Object>()}}} style methods work here similarly to the related object assignments for individual {{{Grid}}} objects.  Aliases, such as {{{setSeller()}}}, are also valid.  This kind of assignment performs 2 functions:
# Associates the {{{Grid}}} as a constraint for subsequent loading: any retrieval from the repository will correspond to this constraint.
# Any {{{Grid}}} objects already present in the {{{GridSet}}} will be associated with the new {{{Grid}}} according to the context of the {{{set}}} assignment.  Any {{{Grid}}} objects subsequently added (via {{{addGrid()}}} or {{{add<Object>()}}} -- {{{addOrder()}}}, in this case) to the {{{GridSet}}} will //inherit// this association automatically.
Late binding data relationships from {{{generatedOnPublish}}} associated key columns also work as expected.

Note that the syntax for creating a related {{{GridSet}}} is a {{{get<Object>Set()}}} method, rather than a {{{new...}}} method, even if the {{{Grid}}} object being used as the factory is itself new.

A generic {{{GridSet}}} object may also be instantiated and dynamically typed using the {{{GridSet::setType()}}} method, or by adding a {{{Grid}}} object manually: the first {{{Grid}}} in, if the {{{type}}} has not already been explicitly set, will determine the type of the whole {{{GridSet}}}.

!Loading
A {{{GridSet}}} may either be implicitly or explicitly loaded, just as with a {{{Grid}}}.  Implicit load operations will likely be the most common, and take place whenever {{{!GridSet::isLoaded()}}} and {{{GridSet::canLoad()}}} //and// when no {{{Grid}}} objects have manually been added to the set.  This pattern is evoked whenever any of the following calls are used:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$count&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRecordCount</span><span style="color: #007700">();&nbsp;</span><span style="color: #FF8000">//&nbsp;also&nbsp;getGridCount()<br /></span><span style="color: #0000BB">$count&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getTotalRecordCount</span><span style="color: #007700">();&nbsp;</span><span style="color: #FF8000">//&nbsp;also&nbsp;getTotalGridCount()<br/><br/></span><span style="color: #FF8000">//&nbsp;Typed&nbsp;and&nbsp;Generic&nbsp;names&nbsp;are&nbsp;available:<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getFirstOrder</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getNextOrder</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getFirstGrid</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getNextGrid</span><span style="color: #007700">();<br /><br /></span><span style="color: #FF8000">//&nbsp;Iterator&nbsp;interface,&nbsp;not&nbsp;normally&nbsp;called&nbsp;directly<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">reset</span><span style="color: #007700">();<br /></span><span style="color: #FF8000">//&nbsp;Usually&nbsp;called&nbsp;implicitly&nbsp;like&nbsp;this:<br /></span><span style="color: #007700">foreach(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span>}</span></span></html>

Explicit load options include:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Load</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$success&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">LoadNextPage</span><span style="color: #007700">();</span></span></html>

Regardless of which is used, at most {{{GridSet::getPageSize()}}} records will be retrieved from the repository.  For {{{LoadNextPage()}}}, that many //more// records will be retrieved and added to the end of the existing list of records.  This does not {{{rewind}}} the iterator, so continued calls to {{{next}}} will succeed, picking up where it left off:

<html><span style="font-family: monospace;">
<span style="color: #007700">while(&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">LoadNextPage</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">'Page&nbsp;no.&nbsp;'</span><span style="color: #007700">.(&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPageOffset</span><span style="color: #007700">()&nbsp;+&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">).</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"--------------------\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;while(&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getNextOrder</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Date</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;echo&nbsp;</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />}</span></span></html>

!Population
In addition to loading from the repository, {{{Grid}}} objects may be manually added to the Set.  This can be done through 3 different methods that are simple aliases for convenience:

<html><span style="font-family: monospace;"><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">add</span><span style="color: #007700">(&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">()&nbsp;);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">addGrid</span><span style="color: #007700">(&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">()&nbsp;);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">addOrder</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">()&nbsp;);</span></span></html>

The first 2 take a second optional ''boolean'' argument for specifying whether or not the {{{GridSet}}} relationships should also be applied to the new incoming {{{Grid}}} object (defaults to true).  The typed {{{add<Object>}}} method assumes ''true'', and expects all arguments to be {{{Grid}}} objects, allowing for multiple objects to be added at the same time.

There is not currently an explicit mechanism for removing objects from the collection.

!Iteration
There are 3 different mechanisms for iterating through {{{GridSet}}} contents:

<html><span style="font-family: monospace;"><span style="color: #007700">for(&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">0</span><span style="color: #007700">;&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">&lt;&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getRecordCount</span><span style="color: #007700">();&nbsp;</span><span style="color: #0000BB">$i</span><span style="color: #007700">++&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrder</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}<br /><br />foreach(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}<br /><br />while(&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getNextOrder</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}</span></span></html>

Each of these will implicitly load a single page if the {{{GridSet}}} has not already loaded, and iterate over the current contents in order of load (based on sort order - see below).

!Pagination
Pagination refers to retrieving data one "page" at a time, or a pre-determined number of records optionally starting at an offset.  This is most likely to be useful within web applications, where only so many records can be effectively displayed on a page, and the interface will be moving between pages.  The number of records on a page can be set either on the {{{GridSet}}} directly by calling {{{GridSet::setPageSize()}}}, or by setting the global {{{PageSize}}} [[configuration option|Config: Options]].  The default is {{{-1}}}, which equates to "unlimited."  This is rarely convenient however, and is only set to this default in order to avoid risking an even less convenient setting by guessing at the needs of the end user.

The available methods and their operations include:
* {{{GridSet::getTotalRecordCount()}}}: Assuming {{{GridSet::canLoad()}}}, returns the total number of records available in the repository.  Can also be called as {{{GridSet::getTotalGridCount()}}}.
* {{{GridSet::getNumberOfPages()}}}: Using the total record count and current page size, returns the total number of pages (note that the last page may contain between 1 and {{{GridSet::getPageSize()}}} records)
* {{{GridSet::setPageOffset()}}}: Sets the 0-based page offset for the next record fetch; defaults to 0.  Note: this method will not produce an error or warning of the page offset is greater than {{{GridSet::getNumberOfPages() - 1}}}; it will however fail to produce any records at that offset.  Can be retrieved using {{{GridSet::getPageOffset()}}}.
* {{{GridSet::setGridOffset()}}}: Sets a specific grid count (rather than page count) offset in order to start at a more arbitrary point, should you so choose; defaults to 0.  Can be retrieved using {{{GridSet::getGridOffset()}}} - which will also be available after {{{GriSet::setPageOffset()}}} calls, which can be useful in constructing informative text:
<html><span style="font-family: monospace;"><span style="color: #007700">echo&nbsp;</span><span style="color: #DD0000">'Showing&nbsp;Orders&nbsp;'</span><span style="color: #007700">.</span><span style="color: #0000BB">number_format</span><span style="color: #007700">(&nbsp;(&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getGridOffset</span><span style="color: #007700">()&nbsp;+&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">),&nbsp;</span><span style="color: #0000BB">0&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;.</span><span style="color: #DD0000">'&nbsp;through&nbsp;'</span><span style="color: #007700">.</span><span style="color: #0000BB">number_format</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">min</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getTotalRecordCount</span><span style="color: #007700">(),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;(&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPageOffset</span><span style="color: #007700">()&nbsp;+&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">)&nbsp;*&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPageSize</span><span style="color: #007700">()&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">0<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">);</span></span></html>

A nice short example of setting page size and offset is:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$pageNumber&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">2</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">12345&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderSet</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Date&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setPageSize</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">50&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setPageOffset</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pageNumber&nbsp;</span><span style="color: #007700">-&nbsp;</span><span style="color: #0000BB">1&nbsp;</span><span style="color: #007700">);<br /><br />foreach(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}</span></span></html>

''NOTE:'' Calling {{{$order->getNumberOfPages()}}} does an implicit {{{$order->getTotalRecordCount()}}}, which causes an implicit load at whatever the current {{{$order->getPageOffset()}}} may be.  This means that, if you are going to validate the requested page number against the number of available pages, you need to set the page number first.  The count will still return a valid total count regardless of whether there are any records available at the specified offset, this just mitigates the risk of returning both the first (default) page and a subsequently requested page, making the iteration potentially twice as large (and somewhat ambiguous in its contents) as expected.  There is not currently a supported method for retrieving the available record count that does not also load at least 1 page worth of data - sorry about the inconvenience.

In the native {{{DataStore}}} adapters, pagination controls are exercised within the repository for performance.  All page fetches are based on the current sort order - it is recommended that this //not// be changed between successive page loads, or unexpected results (and record duplication) may occur.

!Sorting
The sorting options for a {{{GridSet}}} apply only to the order in which the records will be retrieved from the database, and will not sort the contents of an already loaded (or user populated) {{{Set}}}.  Sorting may be done by any {{{Column}}} of any {{{Grid}}} involved with the loading (see ''Criteria'' below), and certainly by the {{{Grid}}} type of the {{{Set}}} itself.

This introduces one of the advanced aspects of Torpor.  Whereas an individual {{{Grid}}} object has the option to call the {{{Column}}} members in method context to return an object, Torpor provides a similar mechanism for returning the official internal key name of any {{{Grid}}} or its {{{Column}}} members.  Called with a {{{Grid}}} name in a member-fetch {{{get}}} context, it will return the key name of that {{{Grid}}}:

<html><span style="font-family: monospace;"><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">;</span></span></html>
Produces:
{{{
ORDER
}}}

The {{{Grid}}} name may be specified using the same case-insensitive and underscore agnostic conventions already established, and will always return the same result.  It also validates the requested {{{Grid}}} name, and will throw a {{{TorporException}}} if it is not found as a member of this instance.

If the same call is made in method context, it will return a {{{GridColumnCollection}}} class which contains all of the {{{Column}}} names for the requested {{{Grid}}}, and which may then in turn be accessed as members (not methods) using the same case-insensitivity (etc.) to produce the official Torpor key name for that {{{Column}}}:

<html><span style="font-family: monospace;">
<span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">SellerID</span><span style="color: #007700">;</span></span></html>
Produces:
{{{
SELLERID
}}}

This has use in sorting because the {{{Column}}} by which to sort the records as retrieved from the repository must be specified in the {{{GridSet::sortBy()}}} will be validated by the Torpor instance to ensure it can be properly constructed into the resulting command by the {{{DataStore}}} for the repository.  If the {{{Column}}} belongs to the same {{{Grid}}} type as the {{{GridSet}}} itself, only that name needs to be provided.  If it is a member of any other {{{Grid}}} type, both the {{{Grid}}} and {{{Column}}} names must be specified.  Or, a literal {{{Column}}} object may be provided in which case the matching {{{Grid}}} and {{{Column}}} names will be extracted.

Thus the range of possible sorting invocations include:

<html><span style="font-family: monospace;"><span style="color: #FF8000">//&nbsp;Member&nbsp;Column&nbsp;name<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Date&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;Grid&nbsp;name,&nbsp;Column&nbsp;name<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">UserName<br /></span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;Literal&nbsp;Column&nbsp;object<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">()&nbsp;);</span></span></html>

Successive calls to {{{GridSet::sortBy()}}} append the requested sorting specification to the end of the current list.  This may be cleared out at any time by calling {{{GridSet::resetSort()}}}.  The return type of the {{{GridSet::sortBy()}}} method is a reference to the {{{GridSet}}} object itself, which allows for chaining:

<html><span style="font-family: monospace;"><span style="color: #FF8000">//&nbsp;Chained&nbsp;sort<br /></span><span style="color: #0000BB">$orderSet<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Date&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">UserName&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">()&nbsp;);</span></span></html>

An optional final (either 2nd or 3rd, depending on the context of the method) argument specifies the order of the sort.  This needs to be one of the related {{{GridSet}}} class sort order constants:
* {{{GridSet::ORDER_ASCENDING}}}: Order from lowest to highest (default).
* {{{GridSet::ORDER_DESCENDING}}}: Order from highest to lowest.
* {{{GridSet::ORDER_RANDOM}}}: Random ordering; not all {{{DataStore}}} adapters support this.

Example:
<html><span style="font-family: monospace;"><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">sortBy</span><span style="color: #007700">(<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Date</span><span style="color: #007700">,<br/>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">GridSet</span><span style="color: #007700">::</span><span style="color: #0000BB">ORDER_ASCENDING<br/></span><span style="color: #007700">);</span></span></html>

All of these sorting examples have used the {{{$MyTorpor}}} instance as a starting point.  There is also a magical shortcut to providing similar functionality in singleton contexts due to the fact that PHP allows for duplication of keywords between class names and function names, so in addition to the {{{Torpor}}} class there is also a {{{Torpor}}} global function whose sole responsibility is to return the singleton instance of the similar object.  The {{{Grid}}} and {{{Column}}} name examples above could be rewritten as:

<html><span style="font-family: monospace;"><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br />echo&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">SellerID</span><span style="color: #007700">.</span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;</span></span></html>
Produces:
{{{
ORDER
SELLERID
}}}

It is of course also possible to pass textual names directly in anything that evaluates to a string, and the same rules of case-insensitivity and underscore agnosticism still apply.  These will be validated and exceptions thrown if not recognized - the only reason the {{{Torpor-><Object>}}} variants are recommended is for tighter control and a preference for not using string literals in implementing code anywhere it may otherwise be avoided.

!Relationships
The whole {{{GridSet}}} may be associated with other {{{Grid}}} objects in any way that the underlying {{{Grid}}} (the type of which the {{{GridSet}}} is) can, allowing for efficient bulk operations.  This means that an entire Set of {{{Order}}} objects may be mapped to the same {{{User}}} at the same time (or more likely, a series of products added to an order - but that's not supported in our simple sample set).  This is done most efficiently using the direct {{{set<Object|Alias>}}} methods, but there are also generic versions for dynamic typing and broader handling:

<html><span style="font-family: monospace;"><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSellert</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$otherUser&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSourceGrid</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSourceGrid</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$otherUser</span><span style="color: #007700">,&nbsp;</span><span style="color: #DD0000">'Seller'&nbsp;</span><span style="color: #007700">);</span></span></html>

Both pairs of calls accomplish identical operations in an identical order.  The term {{{source}}} is used when referring to the incoming {{{Grid}}} object because it will act as part of the generated criteria in loading contents from the repository.  These calls will also apply the same assignment in the same context to every {{{Grid}}} currently contained in the set, either assigning associated data or linking reference columns as appropriate based on system settings.  This behavior may optionally be controlled or overridden by passing a ''boolean'' argument to the assignment method - for typed assignments such as {{{setOrder}}} this will be the second argument, whereas for the generic {{{setSourceGrid}}} it will be the third argument, following any alias specification.  If no alias is in use this may be passed as anything which evaluates to ''false''.  A literal ''false'' value isn't a bad idea.

Retrieval of these objects is similar:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$otherUser&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getSeller</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$user&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getSourceGrid</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'User'&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$otherUser&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getSourceGrid</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Seller'&nbsp;</span><span style="color: #007700">);</span></span></html>

Calling {{{get<Object>}}} as a typed name where the object does not exist will throw a {{{TorporException}}}.  Calling {{{getSourceGrid}}} for an unknown or unassigned {{{Grid}}} will return ''false''.

!Criteria
Any source grid (see {{{Relationships}}} above) implicitly become part of the criteria used to retrieve records from the repository.  While this is useful, it's often not restrictive enough, in that a smaller subset of records is desired, such as those which correspond to a certain date range or shipping type (in our {{{Order}}} example), etc.

Torpor supports a broad range of {{{Criteria}}} objects to provide this functionality, which {{{Criteria}}} may apply to any data member of the {{{Grid}}} type being retrieved, or of any {{{Grid}}} that references it or can be referenced by it.  The comparison values or restrictions may be negated, and/or compared to other {{{Column}}} values within the repository rather than passing the value in directly.  The full range of {{{Criteria}}} types, their arguments and settings, is covered in the [[Appendix]] under ''Class References /'' [[Criteria|Class: Criteria]].

The first argument during creation of a {{{GridSet}}} class may be either a {{{Criteria}}} or {{{Criteria...Set}}} object.  These may also be added after the fact using either the {{{GridSet::setSourceCriteria()}}} or {{{GridSet::addCriteria()}}} methods, which either overwrite or append.  All {{{Criteria}}} added using {{{GridSet::addCriteria()}}} are done so in an ''AND'' context; if this is not the desired behavior, wrap these in a {{{CriteriaOrSet}}} and then add that instead.  Note that all {{{Criteria}}} related operations should be completed before the first loading attempt is made: setting {{{Criteria}}} after the fact will not restrict the populated record set in any way, and in some instances may throw an exception.

All {{{Criteria}}} may also be optionally grouped in either a {{{CriteriaAndSet}}} or {{{CriteriaOrSet}}}, which indicate that "//all// {{{Criteria}}} must match" or "//any// {{{Criteria}}} must match" respectively to qualify a repository record for retrieval.  These may themselves be grouped into {{{Criteria...Set}}} collections, allowing for construction of complex and nuanced logic using simple operations:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">addCriteria</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaBetween</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Date</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'2009-04-09'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'2009-12-12'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #FF8000">//&nbsp;"inclusive"&nbsp;search<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />);<br /><br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">addCriteria</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaAndSet</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaOrSet</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaContains</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'real'&nbsp;</span><span style="color: #FF8000">//&nbsp;case&nbsp;sensitive&nbsp;by&nbsp;default!<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaContains</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'tow'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #FF8000">//&nbsp;case&nbsp;insensitive<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;),<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaNotEndsWith</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">Email</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #DD0000">'aol.com'</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #FF8000">//&nbsp;case&nbsp;insensitive<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;)<br />);</span></span></html>

According to this logic, {{{$orderSet}}} will only retrieve {{{Order}}} objects that:
# Have a {{{Date}}} from 09-Apr-2009 BCE through 12-Dec-2009 BCE, inclusive
# AND are associated with a {{{User}}} that:
## Has an email address containing either "real" (case sensitive) OR "tow" (case insensitive) - the "montreal" and "ottowa" examples from [[The Basics|Examples: Basics]] match.
## AND has an email address that does not end in "aol.com" (case insensitive).

By default, {{{Criteria}}} use the same case-sensitive string comparison as provided by PHP (where supported by the underlying {{{DataStore}}}, which almost all do).  This differs from most string comparison collations in most modern RDBMS implementations, but should lessen the learning curve for approaching Torpor from a PHP perspective in that it matches built-in comparison and sorting operations.

Note that because the various {{{Criteria}}} objects do not belong to the {{{OrderSet}}} directly that both the {{{Grid}}} type name and the member {{{Column}}} name must be supplied in order to indicate to which object these belong (unlike sorting operations, which can assume the {{{Grid}}} type as a starting point).  Any {{{Grid}}} used in the assembly of any {{{Criteria}}} assigned to the {{{GridSet}}} may be used as a specification in {{{GridSet::sortBy()}}}.

Any related {{{Grid}}} objects (from ''Relationships'' above, or from which the {{{GridSet}}} was first created such as in ''Instantiation'' above) will also be part of the resulting criteria assembly used by the {{{DataStore}}} for retrieval from the repository.  The biggest difference is that related {{{Grid}}} objects also provide the implicit assignment capacity to all incoming {{{Grid}}} objects, whereas {{{Criteria}}} are used only to restrict retrieval.

Up: [[Examples]]
Previous: [[Related Objects|Examples: Related Objects]]
Next: [[Advanced Usage]]
Torpor's biggest strength comes not from its automation of [[CRUD]] operations, but its ability to intelligently associate related objects to one another based on the [[foreign key|Config: Keys: Foreign]] mapping in the configuration file.  Any {{{Grid}}} that references or is referenced by any other {{{Grid}}} can be used as a factory to fetch existing or create new instances and records.

This relationship is defined entirely within the XML: whether or not the underlying structure actually supports or enforces foreign references, so long as the configuration file has the right [[foreign keys|Config: Keys: Foreign]] described everything in this section will work.

A word of caution: related object fetches //always// work; that is, they always return a {{{Grid}}} object of the appropriate type, and match up any related values between the objects.  That does not mean that the new object is capable of loading (if the column thus referencing it is //null//, for example) or will be populated with any data.  It's up to the implementing code to make a determination whether or not the new object is viable (the {{{canLoad()}}} method is a good candidate for that).

A second word of caution: Torpor doesn't do anything about relationships when an object is deleted.  For those repositories which support and enforce foreign keys this can get messy very quickly - anything still referring to the object to be deleted will prevent the delete attempt from succeeding, and in fact produce an exception.  It is recommended that this be worked out one of two ways:
# Have appropriate delete handling components in the repository (such as {{{ON DELETE CASCADE}}})
# Override the {{{OnBeforeDelete}}} event of a {{{Grid}}} and manually execute such a cascade by deleting associated collections (performance sucks, but this will also work for those repositories which do have have explicit relationship handling [such as ~MyISAM tables in ~MySQL])

!!~One-to-One Fetch
The relationships defined for {{{Order}}} (see [[simple_sample.xml]]) indicate that it maps directly to {{{User}}} based on primary key.  Because of this, {{{Order}}} can refer to at most a single {{{User}}} object (at least in {{{User}}} context; see below for alias handling), and can be used to fetch a single {{{Grid}}} object matching that description.

This makes sense not only from a convenience perspective, but also in terms of safe enforcement of operations.  The following is perfectly valid code:

<html><span style="font-family: monospace">
<span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">15243&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setId</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserId</span><span style="color: #007700">()&nbsp;);</span></span></html>

But it's not especially pleasant.  It requires manual instantiation of the new object type and explicit population of the related keys; in contexts where multi-column keys are in use this gets tedious very quickly.  The preferred method of the above is:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">15243&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUser</span><span style="color: #007700">();</span></span></html>

This is a special use of the {{{get}}} operation.  The Torpor code determines that a {{{get}}} is desired and analyzes the suffix to determine that we're getting something //other// than a {{{Column}}} belonging to this {{{Grid}}} (which means that it is the user's/developer's responsibility to ensure that no {{{Column}}} entries share names with related {{{Grid}}} objects; it's an unlikely collision, but you have been warned), and seeks to determine if the requested object is known to Torpor and a component of the relationships defined for this {{{Grid}}}.  If not, it will throw a {{{TorporException}}}; otherwise, it will pass the call up the stack to the main Torpor instance and request that a {{{Grid}}} matching the description and the association criteria be produced.  No {{{Key}}} columns need be explicitly populated, and out pops our {{{User}}} object on the other end.

Assuming {{{CacheReferencedGrids}}} is set to {{{true}}} in the [[configuration|Config: Options]], {{{Order}}} will also have an internal member variable set aside for {{{User}}}, and repeated calls to {{{getUser()}}} will return the exact same object instance every time.

!!Using Aliases
{{{Order}}} has a second mapping to {{{User}}}, this time with the {{{referenceGridAlias}}} attribute set to {{{Seller}}}.  This setting provides an alternate name (or context) for this relationship, which is reflected in the invocation pattern:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">15243&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getSeller</span><span style="color: #007700">();</span></span></html>

Again with a special {{{get}}} operation, and this time it's for something other than a {{{Column}}} as well as a any known {{{Grid}}} object; but it //does// match the {{{referenceGridAlias}}} setting, that tells us the {{{Key}}} columns involved and ultimately the type of underlying {{{Grid}}} to fetch.

The {{{User}}} object makes a similar reference, this time to itself:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$userToo&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getReferringUser</span><span style="color: #007700">();</span></span></html>

Something like this makes it possible to traverse a hierarchy with a simple loop:

<html><span style="font-family: monospace">
<span style="color: #007700">while(&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getReferringUserId</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getReferringUser</span><span style="color: #007700">();<br />}</span></span></html>

Note however that this is ''A.'' not very efficient since a repository fetch operation must take place for every object, which then hangs around in memory (see [[Garbage Collection]] in the [[Advanced Usage]] section), and ''B.'' provides no protection against recursion.  The former can be solved in part with a temporary object and an explicit {{{destroy()}}} call, but the latter will require maintaining an identifying list of the {{{Id}}} values traversed to ensure we halt if we encounter a duplicate.

Very few repositories natively support hierarchical queries, and while Torpor does [[support|Supported Persistence Engines]] the data engines themselves, it has no mechanisms for the retrieval of hierarchical data as yet.  Just FYI.

!!Assignment
As is typical, assignment works in the reverse of retrieval, making use of the {{{set}}} keyword in place of {{{get}}}.  It's a simple practice to assign two objects to one another, where Torpor will set all appropriate {{{Column}}} data between the two based on the relationship:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setReferringUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$userToo&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSeller</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$userToo&nbsp;</span><span style="color: #007700">);</span></span></html>

Note that aliases continue to work in these methods as well.

An inevitable question in this type of pattern is, "What about new objects?"  In most modern persistence layers the {{{Primary}}} key of any record is coupled with the repository itself, and is usually not available until after the object has been {{{Publish()}}}'d.  In Torpor, this is indicated by setting a {{{Column}}}'s {{{generatedOnPublish}}} attribute to {{{true}}}.  This allows us to treat it as though it will eventually have data and maintain the intended relationships even if it's between identities just now (but it's prospects will pick up in the future, it swears).  In order for this to work, the global {{{LinkUnpublishedReferenceColumns}}} must also be set to {{{true}}} (which is also the default):

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user&nbsp;&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<span></span></html>

This works.  A call to {{{$order->getUser()}}} will return our selfsame {{{User}}} object.  However, a call to {{{$order->getUserId()}}} will return //null//, because it does not yet have data.  The important thing here is that the //null// it returns belongs to {{{User}}}; because the reference columns have been linked, {{{$order->UserId}}} implicitly pulls data from {{{$user->Id}}} to get its answer.  When it has no data as well, //null// is returned.  If, however, it has been populated (through whatever means), then not only does {{{$order->UserId}}} retrieve that new data but it also sets it for itself and severs the automatic link between the two (assuming that the data is unlikely to change there's no reason to keep redirecting; this can be overridden by setting {{{PerpetuateAutoLinks}}} to {{{true}}}; more information about column-linking can be found in the [[Appendix]] under ''Class References / [[Column|Class: Column]]'').

More importantly, not only does it work, but assuming that the {{{PublishDependencies}}} option is set to {{{true}}} (default), calling {{{$order->Publish()}}} will flush the entire thing to the repository in the necessary order to satisfy those late-binding data assumptions.  This kind of operation //is// recursive safe - if recursion is detected in the process a {{{TorporException}}} will be thrown and the process aborted.  A similar exception will also be thrown if one of the items in the dependency hierarchy cannot publish (lacking required data members, for example).

!!Factories
Instead of manually creating new objects to associate with one another, just as with the fetch ({{{get}}}) and assignment ({{{set}}}) operations it's possible to create new objects from the relationships themselves ({{{new}}}):

This works from both sides of a "one-to-many" relationship such as we've already been using:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newSeller</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$userToo&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newReferringUser</span><span style="color: #007700">();</span><br/><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$userToo</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUserFromReferringUser</span><span style="color: #007700">();</span><br/><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrderFromSeller</span><span style="color: #007700">();</span></span></html>

Note that the use of aliases is supported here as well.  In addition to the {{{new}}} keyword, we have also introduced the {{{From}}} modifier keywork.  Since a {{{User}}} type {{{Grid}}} will always be typed as a {{{User}}}, the way to indicate that it should be treated in the {{{Seller}}} context for the creation of a new {{{Order}}} is by concatenating the modifier and the alias-context together: {{{...FromSeller}}}.  Technically it would also be possible to say {{{newOrderFromUser}}}, in case that level of redundancy were desired; however, since the {{{Order}}} -- {{{User}}} relationship is already defined without alias-context qualifier this is purely optional. 

For all objects created using the {{{new}}} methods, those which already contain the referring data will be assigned over to the related columns in the new object automatically.  Those without data, marked as {{{generatedOnPublish}}}, with the global {{{LinkUnpublishedReferenceColumns}}} option set to {{{true}}}, will be associated as linked dependencies just as in the prior example.

!!Sets (~One-to-Many Fetch)
So far all of our examples have dealt with single objects, where the corresponding object on the other side of the operation was unambiguous.  Since we're dealing with one-to-many relationships however, it only makes sense to explore the retrieval of object collections.  A collection of objects in Torpor is referred to as a {{{Set}}}, and is instantiated as a {{{GridSet}}} object (or {{{TypedGridSet}}}, if {{{TypedGridClasses}}} are enabled).  This is not to be confused with the {{{set}}} assignment verb, which will only ever take place at the very beginning of a method name.  As referring to a collection, {{{Set}}} will always follow a {{{Grid}}} object name qualifier or alias:

<html><span style="font-family: monospace;">
<span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderSet</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderSetFromSeller</span><span style="color: #007700">();<br /><br /></span><span style="color: #0000BB">$userToo&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserSetFromReferringUser</span><span style="color: #007700">();</span></span></html>

In these examples, not only are aliases supported, but the {{{From}}} modifier can also be used as with the prior examples.  Creation or retrieval of a {{{Set}}} is only supported from the "one" side of a "one-to-many" relationship; {{{$order->getUserSet()}}} will produce an exception.

The use and treatment of collections is covered more extensively in the [[next|Examples: Collections and Criteria]] section, which contain examples for retrieving and manipulating the contents as well as restricting them to specific subsets.

Up: [[Examples]]
Previous: [[The Basics|Examples: Basics]]
Next: [[Collections and Criteria|Examples: Collections and Criteria]]
Torpor really likes exceptions, and uses them all over the place whenever it encounters a situation beyond which it cannot reasonably proceed.  In standard practice these should be unlikely, though during active development they can occur quite regularly as the kinks are worked out.  Regardless of whether you actually expect them, expect them, and handle them correctly.  This can be done either by wrapping everything in {{{try}}}/{{{catch}}} blocks, or by ensuring a default exception handler has been registered.

It is always a good idea to catch exceptions, using whatever mechanism you feel appropriate, or at the very least Never Showing Your Errors On the Front End; especially where descriptive error messages are used these can be at the very least unprofessional, and at the worst provide information about the underlying operation of the code or the repository which can be used in attacks.

The error messages provide by Torpor try to be verbose enough that it's easy to determine exactly what the code was attempting to do when it encountered the error.  It will indicate the type of {{{Grid}}} and operation in question, and the stack trace will let you know the exact lines in each of the files on the stack through which that operation passed before encountering its demise.  As is the case with most frameworks, there is even some abstraction in place when it comes to throwing exceptions in order to leverage a standardized routine.  This usually means that the last few lines (depth-wise) in the stack will be the result of those methods and can readily be ignored:
{{{
Could not connect to MySQL using supplied credentials: Can't connect to MySQL server on '127.0.0.1'
#0 /torpor-php/src/ANSISQLDataStore.php(408): Torpor::throwException('Could not conne...')
#1 /torpor-php/src/MySQLDataStore.php(111): ANSISQLDataStore->throwException('Could not conne...')
#2 /torpor-php/src/MySQLDataStore.php(131): MySQLDataStore->connect()
#3 /torpor-php/src/MySQLDataStore.php(310): MySQLDataStore->getConnection()
#4 /torpor-php/src/MySQLDataStore.php(315): MySQLDataStore->escape('ORDER', true, '`')
#5 /torpor-php/src/ANSISQLDataStore.php(678): MySQLDataStore->escapeDataName('ORDER')
#6 /torpor-php/src/ANSISQLDataStore.php(230): ANSISQLDataStore->CriteriaToSQL('ORDER', Object(CriteriaAndSet), Array)
#7 /torpor-php/src/Torpor.php(1152): ANSISQLDataStore->LoadSet(Object(Orderset), false)
#8 /torpor-php/src/GridSet.php(205): Torpor->Load(Object(Orderset), false)
#9 torpor-php/src/GridSet.php(528): GridSet->Load()
#10 /torpor-php/src/test/example.php(56): GridSet->rewind()
#11 {main}
}}}

Line 56 from the mythical {{{example.php}}}:

<html><span style="font-family: monospace;"><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">foreach(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">){<br /></span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/</span></span></html>

The {{{foreach}}} loop causes an implicit {{{rewind}}} operation on the iterator interface, which in turn causes an implicit load (this {{{OrderSet}}} having not previously loaded), each just-in-time operation cascading all the way up to the connection attempt and so on until throwing the actual exception on lined {{{#0}}} and {{{#1}}} in the printed stack trace; these can be ignored then, and looking at the line {{{#2}}} we can see that the attempted operation was {{{MySQLDataStore->connect()}}}; those this is also apparent from the text of the exception itself.

The actual exception will be thrown as an object of type {{{TorporException}}}.  This inheritance provides absolutely no new or changed functionality over the standard PHP {{{Exception}}} class except that it allows for {{{catch}}} blocks to be selective.  Catching {{{Exception}}} will get not only {{{Exception}}} but everything that descends from it; catching {{{TorporException}}} instead will catch only that type (and its descendants, of which there are none natively defined), allowing quick differentiation and propagation of errors through multiple catch blocks:

<html><span style="font-family: monospace;"><span style="color: #007700">try&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;try&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">}&nbsp;catch(&nbsp;</span><span style="color: #0000BB">TorporException&nbsp;$e&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Something&nbsp;anomalous&nbsp;happened&nbsp;in&nbsp;Torpor&nbsp;code<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMessage</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}&nbsp;catch(&nbsp;</span><span style="color: #0000BB">Exception&nbsp;$e&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">//&nbsp;Something&nbsp;anomalous&nbsp;that&nbsp;almost&nbsp;certainly&nbsp;doesn't<br />&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;originate&nbsp;from&nbsp;Torpor&nbsp;itself&nbsp;or&nbsp;its&nbsp;attempted<br />&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;operations.<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">echo&nbsp;</span><span style="color: #0000BB">$e</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getMessage</span><span style="color: #007700">();<br />}</span></span></html>

The inner block will catch anything specifically Torpor related, as indicated in the comments, whereas the exterior block would catch anything it didn't (or which it chose to re-{{{throw}}}).  It can be pretty unwieldy to wrap many common operations in {{{try}}}/{{{catch}}} blocks though, so unless there's a good reason for doing it (knowingly attempting something risky that's likely to fail on a specific operation) it's probably better practice to register a default exception handler which can itself differentiate on which kind of Exception it's been fed; with the additional caveat that after the default handler is invoked by PHP, the program ''will'' exit, so this doesn't fully replicate the functionality of {{{catch}}} which can allow the code to continue beyond the point of error if desired.

Torpor also produces {{{E_USER_WARNING}}} notices whenever it's making an informed but dangerous guess potentially resulting in undesired behavior, such as the truncation of data or precision, issues with character encoding, or some complex relationship management behaviors where an inference has been made as to which of multiple likely scenarios it has defaulted to when multiple ambiguous choices are available.  The code itself has been made {{{E_STRICT}}} compliant across the board, so it's safe to turn on whatever level of logging is desired without a lot of operational noise.

Up: [[Advanced Usage]]
Previous: [[Garbage Collection]]
Next: [[Extension]]
Basic Torpor operations are useful for automating [[CRUD]] and navigating object relationships.  This provides a significant boost in development productivity, but those automated factories are fairly bare and don't provide support for business logic or advanced validation.  Fortunately Torpor has ample support for extension of its primitives to provide this kind of enhancement.

First we'll look at 2 examples for extending individual {{{Column}}} classes, followed by a {{{Grid}}} demonstration, with summary notes at the end.
!Boolean Column
The {{{Column}}} class technically has 2 parallel {{{getData}}}/{{{setData}}} avenues: one for use to and from PHP data, the other for data originating from or destined for the repository.  This allows for any arbitrary translation from usage of the data in PHP vs. what's eventually fed into the data store.  Useful examples include date translation, transparent encryption/decryption, or support for PHP primitives not fully supported by the repository.

For example, many databases lack support for a simple boolean column definition, using instead a very small integer or a character enumeration.  Torpor provides support for working with boolean column members natively in PHP, so that every interaction can rely on simple ''true''/''false'' evaluation rather than remembering whether it needs to use ''Y''/''N'', etc.  Assuming a ''Y''/''N'' enumeration, let's implement a {{{CharBool}}} class for mapping ''true''/''false'' states:

<html><span style="font-family: monospace;"><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">CharBool&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Column<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">getPersistData</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$localOnly&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getData</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$localOnly&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;!</span><span style="color: #0000BB">is_null</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">?&nbsp;</span><span style="color: #DD0000">'Y'&nbsp;</span><span style="color: #007700">:&nbsp;</span><span style="color: #DD0000">'N'&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">validatePersistData</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">null</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;!</span><span style="color: #0000BB">is_null</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;</span><span style="color: #0000BB">strtoupper</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)&nbsp;==&nbsp;</span><span style="color: #DD0000">'Y'&nbsp;</span><span style="color: #007700">?&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #007700">:&nbsp;</span><span style="color: #0000BB">false&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$return&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></span></html>

For starters, all extending classes need to literally {{{extend}}} the class they're adding to (in this case, {{{Column}}}).  This allows it to continue working in the Torpor framework without having to re-implement all of the other components of the interface (though if this is desired it's still possible, just not recommended; see the class and interface references in the [[Appendix]]).

We then override 2 {{{public}}} functions:
* ''{{{getPersistData}}}:'' this method is called by the {{{DataStore}}} implementations when feeding data from the class back to the repository.  In order to be compatible with the rest of the framework it must make use of the {{{getData}}} method internally, passing any ''boolean'' argument it receives, which indicates the context of the retrieval (e.g., whether we want the copy of the data inherent to the class or whether to auto-populate and/or follow linkage to other {{{Column}}} objects for the target data).  This keeps all the internal state management in the proper order and context and any associated just-in-time activation that this or other objects may be relying on intact.  Optionally returning {{{null}}} is also important, whether or not the {{{Column}}} itself is considered nullable: if the {{{Column}}} does not have a {{{default}}} value specified in the [[configuration|Config: Columns]], {{{null}}} should be used to indicate a lack of value assignment.  Or for a nullable {{{Column}}}, obviously, the 3rd state is valid even for a traditionally 2-state data type such as this.  The final data returned from this method will be the data fed into the repository; it is the responsibility of the {{{DataStore}}} to provide any data encapsulation or escaping, so don't worry about that here.
* ''{{{validatePersistData}}}:'' this method is used during {{{setData}}} operations when the data comes from repository.  It is responsible for evaluating the single argument provided under the assumption of its originating in the repository, providing any warnings or exceptions, modifying the data as appropriate, and returning the final value for use within PHP.  Nullable data needs to be considered here as well.

With these 2 methods in place, the repository will see any of ''Y''/''N''/''null'' as appropriate, and PHP will get its own ''true''/''false''/''null''.  The last requirement for fitting this into the Torpor deployment is hooking it into the configuration, setting the {{{class}}} attribute of a {{{Column}}} to {{{CharBool}}}, or a {{{DataMap}}} entry for {{{boolean}}} types.  Note that an enumeration or {{{CHAR(1)}}} data type in the repository will be set to a data type of {{{char}}} or {{{varchar}}} in the XML by the [[repository extraction scripts|Repository Extraction]], and will need to be changed to ''boolean'' for this class to really make sense.
!Password Hash Column
In addition to validation and translation to and from the repository it's also possible to provide validation when working with data on the PHP side.  This would apply to any area where simple data type, encoding, and length constraints are not sufficient for maintaining data quality, or where more nuanced controls or implicit translation is desired.

In this example, the {{{validate}}} method is extended to ensure that a business-logic constraint is in place such that the {{{Username}}} and {{{Password}}} members of a {{{User}}} type {{{Grid}}} may not be the same, and also transparently encode the incoming value into an MD5 hash to obscure it for security purposes.

<html><span style="font-family: monospace;"><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">PasswordHash&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Column<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">validatePersistData</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">validate</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;</span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)&nbsp;==&nbsp;</span><span style="color: #0000BB">strtolower</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">User</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">getUserName</span><span style="color: #007700">()&nbsp;)&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">throwException</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Password&nbsp;cannot&nbsp;be&nbsp;identical&nbsp;to&nbsp;username'&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$data&nbsp;</span><span style="color: #007700">)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></span></html>

Again, the data management in the {{{validate}}} method is responsible for producing any errors, notices, or exceptions, and returning an appropriately sanitized or otherwise translated value to be stored internally (and accessed via {{{getData}}} mechanisms).  Also as with the prior example, the {{{PasswordHash}}} class needs to be wired up to the {{{type}}} attribute of a {{{Column}}} object in the [[configuration|Configuration]] before it can be used.

Note that {{{validatePersistData}}} is also extended, in this case to provide a blind pass-through on the value it receives.  This is because the native implementation of {{{validatePersistData}}} in the {{{Column}}} class simply uses the method as a facade to the {{{validate}}} method; were this to retain that definition, every time the affected {{{Column}}} object were populated from the database it would become an MD5 hash of the already encoded value, very quickly destroying data integrity.  This patten is used (as opposed to the non-validating example shown here) to ensure data integrity at all touch points, and should not cause issues except for rarely when extending, or even more rarely if the repository and {{{Column}}} definition are ill-suited to one another (or there are horrible data issues).
!User Grid
{{{Grid}}} objects can be extended just as {{{Column}}} objects can.  This can include modification to the base class methods or completely new options and attributes, as shown here:

<html><span style="font-family: monospace;"><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">User&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">Grid<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;</span><span style="color: #0000BB">MD5_REGEX&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'/^[A-Fa-f0-9]{32}$/'</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;</span><span style="color: #0000BB">passwordMatch</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw1</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;!</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">MD5_REGEX</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">)&nbsp;?&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">)&nbsp;:&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;!</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">MD5_REGEX</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)&nbsp;?&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)&nbsp;:&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">isUserPassword</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$password&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">passwordMatch</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$password</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPassword</span><span style="color: #007700">()&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></span></html>

Static methods, class constants (highly recommended over string literals directly within the code), and business logic are added as with any other PHP class.  Making use of the implicitly available {{{getPassword}}} method in the {{{isUserPassword}}} example invokes all the same just-in-time loading as it would otherwise, and the provision of static methods allow for the encapsulated business logic to be leveraged generically.  More especially, it keeps all of the logic for what constitutes a password, how it is encoded and compared, to reside within the {{{User}}} class (and by association, possibly the {{{PasswordHash}}} example from above).  Implementing code leveraging these methods need not be concerned with any of those mechanisms directly, which makes modification or migration to other means a well-contained solution in any future revisions.

As with the {{{Column}}} class extension examples, the {{{User}}} class will need to be plugged into an associated {{{Grid}}} definition in the [[XML configuration|Config: Grids]] in order to be automatically instantiated wherever this {{{Grid}}} type is requested.
!Events
The {{{Grid}}} class supports a rich event model, with several methods called automatically at specific times by the corresponding Torpor operation.  Each of these is invoked with no arguments, and no return value is expected.
# ''{{{OnNew}}}:'' Called directly after a new object has been created (and, with the exception of [[TypedGrid]]s, prior the the assignment of any passed arguments).
# ''{{{OnLoad}}}:'' Called immediately following the initial {{{Load}}} of an object, implicit or explicit, regardless of whether the contents originate from an intermediate cache or the repository.
# ''{{{OnBeforePublish}}}:'' Called just //prior// to publishing the contents to the repository, but after any evaluation has been made as to the fitness of the publishing attempt; this should not be used as a method for providing just-in-time values to make publishing viable, since that evaluation has already concluded by the time this is reached (and won't be reached if the evaluation failed).
# ''{{{OnPublish}}}:'' Called immediately following a successful {{{Publish}}}.
# ''{{{OnBeforeDelete}}}:'' Called just //prior// to removing a {{{Grid}}} from the repository.
# ''{{{OnDelete}}}:'' Called immediately following a successful {{{Delete}}}, but after the {{{Grid}}} has been un-loaded and reset to a default state, so identifying data members will not be available.  Technically this could be seen as analogous to {{{OnNew}}}, but each are called discretely in their own circumstances.

Extending these methods allows one to hook into these events with whatever logic or operations they see fit.  A built-in {{{DebugGrid}}} class does exactly this, providing {{{E_USER_NOTICE}}} indications of when each of the events fire without actually modifying any of the operations.
!Epilogue
Extended classes properly configured within the XML will be used whenever the affected {{{Grid}}} or {{{Column}}} object comes into play, no matter the context.  This applies to both {{{Grid}}} and [[TypedGrid]] classes (as does the extension example provided above), providing several implementation options to fit virtually any environment.

While this extension of Torpor primitives is well supported, even extension of the magical {{{get<ObjectTypeName>}}} style methods, they are not easily "reflected" in terms of determining what methods or members exist on a given class.  This is because so much of the functionality is provided via PHP's own magical {{{__get}}}, {{{__set}}}, and {{{__call}}} methods.  There are other means of accessing this kind of information which are covered in the class reference section of the [[Appendix]].

Up: [[Advanced Usage]]
Previous: [[Exceptions]]
Next: [[Sessions]]
Torpor is categorized by the following features:
!!!Dynamic Factories
There is no code generation step for setting up and using Torpor.  It is necessary to create a [[configuration|Configuration]] file which describes the Grid structure(s) and the underlying repository via XML, but once that's done (and it can be done automatically using the included [[repository extraction scripts|Repository Extraction]]) it is not necessary to generate any PHP code for classes: everything happens from that configuration on-the-fly (though cached after just-in-time analysis as appropriate for performance).
!!!Relational Factories
Any Grid with a defined relationship to any other Grid type can be used to retrieve or create instances of the related Grid.  For example (as laid out in [[simple_sample.xml]] and illustrated in [[Getting Started|Getting Started with Torpor]]), a {{{User}}} Grid is referenced by {{{Order}}}, which implies a one-to-many relationship.  This means that {{{User}}} can be used to retrieve a set ({{{GridSet}}}) of {{{Order}}} instances directly, or to spawn new {{{Order}}} objects as desired.  The reciprocal operates predictably: any {{{Order}}} can be used to retrieve the associated {{{User}}} object from the repository.

Also as illustrated in this example, it's possible to have as many relationships between Grids as there are Columns, including multiple relationships between the same types under different contexts.  Multiple-column keys and relationships are also supported out of the box, as are self referential relationships (as with {{{User}}} to {{{User-as-ReferringUser}}}).
!!!Loose Typing With Attitude
Torpor makes extensive use of the special {{{__call}}}, {{{__get}}}, and {{{__set}}} PHP methods.  These allow for on-the-fly analysis and redirection of the requested methods or variables, which are used in lieu of attempting to create getters and setters for all related objects, columns, etc.  It also means that relaxed (one might say undisciplined) access patterns still benefit from all the rigor and control that went in to making the framework {{{E_ALL|E_STRICT}}} friendly, if not encouraging them outright (though discipline is still urged for the sake of consistency and maintainability; whatever style you're going to use, pick that and stick with it) by making all accessors case-insensitive.  It's also completely indifferent to the placement of underscores, which are commonly used in case-insensitive RDBMS definitions: {{{$x = $object->getTheColumn();}}} is the same as {{{$x = $object->getTHE_COLUMN();}}} is the same as {{{$x = $object->TheColumn;}}} or {{{$x = $object->THE_COLUMN;}}} (and likewise the reverse for {{{set}}} operations).

Behind this very malleable facade it's still necessary to play nice with the repository, which is almost never as forgiving as PHP (~SQLite is an outlying exception).  String/Byte length, character set encoding, numeric precision, date formats, etc., are all strictly controlled and validated so there should be no surprises down the line.  {{{E_USER_WARNING}}} notices are provided whenever precision is lost or truncation occurs, making debugging unanticipated data management issues from real-world scenarios much easier.
!!!Just In Time
Information is not loaded from the repository until it's needed, keeping objects low in memory consumption and distributing (and in many cases negating) load from a traditional all-up-front pattern to the actual moment of use.  This is married with good repository management as well: the first time an un-loaded Column member of a Grid is accessed, the entire Grid is populated.  Likewise, when retrieving ~GridSet contents, rather than extracting required identifying components (such as primary or unique keys) and then filling in the details piecemeal for each instance after the fact, since it's touching all the same information anyway the whole bundle (however small or large it may be based on pagination constraints) is slurped up and instantiated locally within the application; this relatively small memory trade-off can save countless round-trips to remote resources and dramatically increase application performance while decreasing repository load.

Thus, individual objects which are likely to comprise the majority of an applications operations keep things nimble where they can, and bulk operations more likely to strain the repository or network do their part as well, each in their own way.  The end developer and user experience is seamless.
!!!Caching
Read- and Write- Through caching means that every Grid instance as it moves from or to the repository can optionally be made available in a nearby location for quick retrieval next time it's needed.  By dedicating a limited amount of memory to simple hash-based access it's possible to negate many round trips to the repository.  Not every situation can benefit from caching, but those with a heavy reliance on frequently accessed and infrequently changing data (such as content management, eCommerce, and many web applications) can see significant performance boosts.  This is especially true with distributed caching (such as via the included Memcache adapter), which will allow multiple threads on the same machine or multiple machines in the same cluster to share that hash, providing lateral scalability at the application layer with a much lower increase in demand on the repository which is otherwise a typical bottleneck in N-tier strategies.
!!!Extensibility
Every component of Torpor can be readily extended or modified with very little overhead.  By extending the set of intelligent and adaptable primitives, business logic or other enhancements can be encapsulated in simple deltas to modify or expand the existing functionality as necessary.  Complete replacement is also possible, and in many cases encouraged by the use of basic Interfaces for plug-in components.

Combining that class-based extensibility with flexible configuration means that one Column on one Grid can be enhanced just as easily as all Columns of a given data type (or all Grids) across the entire installation.  New ~DataStore or Cache adapters can readily be fit into the existing architecture.

A complete event model also makes targeted extension extremely simple.  By tying into any of the associated {{{OnNew}}}, {{{OnLoad}}}, {{{OnBeforePublish}}}, {{{OnPublish}}}, {{{OnBeforeDelete}}}, or {{{OnDelete}}} hooks that are all fired at their respective times, a great deal of functionality can be added with surgical precision.
!!!Virtual Entities
While the XML configuration is strictly enforced, it need not be founded in reality.  Grids or Columns best not exposed to the application layer (such as trigger provided last-modified timestamp or identities) can simply be omitted.  Along with their descriptive hints, alias names can be used to smooth out or obscure underlying repository design.  Perhaps more powerfully, any standard [[CRUD]] operations can be overridden with the custom [[Command]] entry, which works with the ~DataStore adapter to enhance or completely replace standard accessors.  Stored Procedures can be used for any, all, or none, and even entire views (and as many update statements as you want) or virtual triggers can be defined directly within Torpor for those instances where the repository cannot or should not (or the DBA's are just picky) be provided.

Previous: [[Introduction]]
Next: [[Getting Started|Getting Started with Torpor]]
The Garbage Collection in PHP uses simple reference counting to determine how many entities still believe an object exists, and removing it once that count drops to zero or once the stack terminates (with "global" and "function" being the only 2 granularities of stack supported).

The problem with this as far as Torpor is concerned is that {{{Column}}} objects know to which {{{Grid}}} instance they belong - so even if the {{{Grid}}} itself goes out of scope and is no longer referenced by anything within the stack itself, at least one reference for every {{{Column}}} object will still exist.  Likewise, the {{{Grid}}} references each of the {{{Column}}} members which belong to it, creating a circular dependency.

For standard web applications this isn't a terribly big deal - once the page execution finishes the stack terminates and everything is cleared.  For longer running routines or persistent applications this can really start to add up though, and looks a lot like a memory leak.

The most common source of rapid memory growth is when objects are instantiated as part of a {{{GridSet}}} or within a loop - especially when those objects are not explicitly freed at the end of the loop.  Assuming that there contiguous {{{Order}}} records (from the standard [[Example|Examples]] series), consider the following code:

<html><span style="font-family: monospace;"><span style="color: #007700">foreach(&nbsp;</span><span style="color: #0000BB">range</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">100&nbsp;</span><span style="color: #007700">)&nbsp;as&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}</span></span></html>

Even though the {{{$order}}} variable is overwritten every time, the object to which it previously referred is kept on the stack because internal references persist.  Once {{{$order}}} is reassigned, there is no way to retrieve the prior {{{Order}}} object to which it referred.  That means the above code now has 100 {{{Order}}} objects floating in the ether, each taking up space until the stack to which they belong terminates.  The same is true for an {{{OrderSet}}} style collection:

<html><span style="font-family: monospace;"><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrderSet</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaBetween</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">OrderId</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">100</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #FF8000">//&nbsp;Inclusive<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Load</span><span style="color: #007700">();<br /><br />unset(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">);</span></span></html>

Oven though {{{$orderSet}}} as a variable has been unassigned, the underlying {{{Order}}} objects will still be hanging around.

There is a workaround for this, but it requires manual intervention.  PHP's magic {{{__destruct}}} method needs to be invoked - since we know that's not going to happen automatically, we can call it manually using a common {{{destroy()}}} method:

<html><span style="font-family: monospace;"><span style="color: #007700">foreach(&nbsp;</span><span style="color: #0000BB">range</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">100&nbsp;</span><span style="color: #007700">)&nbsp;as&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$i&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><b><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">destroy</span><span style="color: #007700">();</span></b><br />}<br /><br /><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrderSet</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;</span><span style="color: #0000BB">CriteriaBetween</span><span style="color: #007700">(<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Order</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">OrderId</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">1</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">100</span><span style="color: #007700">,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">true&nbsp;</span><span style="color: #FF8000">//&nbsp;Inclusive<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #007700">)<br />);<br /></span><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Load</span><span style="color: #007700">();<br /></span><b><span style="color: #0000BB">$orderSet</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">destroy</span><span style="color: #007700">();</span></b><br /><span style="color: #007700">unset(&nbsp;</span><span style="color: #0000BB">$orderSet&nbsp;</span><span style="color: #007700">);</span></span></html>

The {{{destroy()}}} method walks through the {{{Grid}}} and explicitly removes the {{{Column}}} objects and back-references, allowing them to leave scope and the {{{Grid}}} object to then leave scope as well.  When called on a {{{GridSet}}} it does this to every member {{{Grid}}} object in turn (without causing any implicit loading to take place).  This does not affect the data in the repository or cache, but it ''will'' affect any variables that still reference an object that has been {{{destroy}}ed; these will cause the persisting variable to produce errors very quickly when attempts are made to access non-existent members.  It is therefor recommended that this be used with extreme caution and care to ensure no toes are stepped on.

Up: [[Advanced Usage]]
Next: [[Exceptions]]
!!Installation
After [[downloading a distribution package|Downloads]] the relevant PHP files will be extracted to a folder like {{{torpor/src}}}.

These source files should be placed so as to be accessible to the PHP include path (or the path modified to incorporate the installation directory). The main {{{Torpor.php}}} file will affect an inclusion of necessary supporting files based on its current directory.

It is recommended to run the provided {{{torpor/src/test/test.php}}} in your target environment to confirm successful installation, dependencies, and operation. Be advised that command line and web server invocations frequently differ in the available environments and settings and may produce different or unexpected results such as failure to include proper files and locate dependent packages. The successful execution should be confirmed in the same conditions you expect to use the package. 
!![[Configuration]]
All configuration is performed via XML, including optional settings, data engine access, and descriptions of the data objects themselves. This XML must be prepared according to the specifications outlined in the more exhaustive [[Configuration]] section of this documentation and will be validated against the included {{{TorporConfig.xsd}}} schema file prior to loading. It is recommended to test this validation manually during development in order to ensure successful loading (which will separate syntax errors from logic errors, making debugging easier). The included {{{torpor/tools/validate}}} script is provided for this purpose.

Torpor will look in the PHP include path for the file {{{TorporConfig.xml}}} by default, unless something else is passed as an argument to the {{{Torpor::initialize()}}} method (or the {{{TORPOR_CONFIG}}} environment variable is set, which may contain either a filename, URI, or even XML content).  This can be passed either as a string containing the XML, a file pointer, file name, ~SimpleXML instance, or URI. For the best performance it is recommended to use file based access rather than reading from ~URIs over the network.  The easiest way to establish the configuration file is by using one of the [[data repository extraction scripts|Repository Extraction]] (available under {{{torpor/tools}}}), which will to the best of its abilities describe the layout of your repository in compatible XML - each comes with its own instructions regarding parameters for invocation.  More details can be found under the [[Configuration]] section.
!!Invocation
Torpor can be used in either instance or singleton modes (although making use of the TypedGrid classes __requires__ singleton operation), and initialization is similar in either case:
!!!Instance
<html>
<span style="font-family: monospace;">
<span style="color: #0000BB">$torpor&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">initialize</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'TorporConfig.xml'&nbsp;</span><span style="color: #007700">);</span>
</span>
</html>
!!!Singleton
<html>
<span style="font-family: monospace;">
<span style="color: #0000BB">Torpor</span><span style="color: #007700">::</span><span style="color: #0000BB">getInstance</span><span style="color: #007700">()-&gt;</span><span style="color: #0000BB">initialize</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'TorporConfig.xml'&nbsp;</span><span style="color: #007700">);</span>
</span>
</html>

From there it's a matter of setting up your first object through the {{{Torpor}}} factory.  Assuming the configuration file is [[simple_sample.xml]] and Torpor is being used without the aid of TypedGrid classes (note that after something like {{{$MyTorpor = new Torpor();}}} and {{{$MyTorpor = Torpor::getInstance();}}} everything is the same; in this usage pattern singleton just guarantees initialization only happens once, and uses less memory for repeat instance acquisitions):

<html>
<div style="font-family: monospace;">
<span style="color: #0000BB">$MyTorpor&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">::</span><span style="color: #0000BB">getInstance</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">initialize</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'simple_sample.xml'&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;get&lt;Object&gt;ById:<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">12345&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;******************************<br />//&nbsp;**&nbsp;&nbsp;Related&nbsp;Object&nbsp;Factory&nbsp;&nbsp;**<br />//&nbsp;******************************<br />//&nbsp;get&lt;Object&gt;Set&nbsp;(implicit&nbsp;"...From&lt;Object&gt;"):<br /></span><span style="color: #0000BB">$orderHistory&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getOrderSet</span><span style="color: #007700">();<br />foreach(&nbsp;</span><span style="color: #0000BB">$orderHistory&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">){&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/&nbsp;</span><span style="color: #007700">}<br /><br /></span><span style="color: #FF8000">//&nbsp;new&lt;Object&gt;&nbsp;(implicit&nbsp;"...From&lt;Object&gt;"):<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$user</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">();<br /><br /><br /></span><span style="color: #FF8000">//&nbsp;***********************************<br />//&nbsp;**&nbsp;&nbsp;Alternate&nbsp;Access&nbsp;Mechanisms&nbsp;&nbsp;**<br />//&nbsp;***********************************<br />//&nbsp;Automatic&nbsp;relationship&nbsp;column&nbsp;traversal&nbsp;and&nbsp;set<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSeller</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">67890&nbsp;</span><span style="color: #007700">)&nbsp;);<br /></span><span style="color: #FF8000">//&nbsp;Identical&nbsp;to:<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSellerId</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">67890&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;The&nbsp;following&nbsp;are&nbsp;equivalent:<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setPurchaseDate</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">date</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Y-m-d&nbsp;H:i:s'&nbsp;</span><span style="color: #007700">)&nbsp;);<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">PurchaseDate&nbsp;</span><span style="color: #007700">=&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">date</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Y-m-d&nbsp;H:i:s'&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">PURCHASE_DATE&nbsp;</span><span style="color: #007700">=&nbsp;&nbsp;</span><span style="color: #0000BB">date</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Y-m-d&nbsp;H:i:s'&nbsp;</span><span style="color: #007700">);<br /><br /><br /></span><span style="color: #FF8000">//&nbsp;**********************************<br />//&nbsp;**&nbsp;&nbsp;Late&nbsp;binding&nbsp;relationships&nbsp;&nbsp;**<br />//&nbsp;**********************************<br /></span><span style="color: #0000BB">$secondUser&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$secondUser</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setReferringUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;$secondUser&nbsp;does&nbsp;not&nbsp;yet&nbsp;exist&nbsp;in&nbsp;the&nbsp;repository,<br />//&nbsp;so&nbsp;this&nbsp;sets&nbsp;up&nbsp;an&nbsp;implicit&nbsp;association&nbsp;that<br />//&nbsp;will&nbsp;retrieve&nbsp;the&nbsp;relational&nbsp;column&nbsp;values&nbsp;when<br />//&nbsp;they&nbsp;become&nbsp;available.<br /></span><span style="color: #0000BB">$order&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$secondUser</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newOrder</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setSeller</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setDate</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">date</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'Y-m-d&nbsp;H:i:s'&nbsp;</span><span style="color: #007700">)&nbsp;);<br /></span><span style="color: #FF8000">//&nbsp;Neither&nbsp;ShippingAddress&nbsp;nor&nbsp;ShippingType&nbsp;are&nbsp;set<br />//&nbsp;up&nbsp;in&nbsp;this&nbsp;example,&nbsp;but&nbsp;you&nbsp;get&nbsp;the&nbsp;idea.<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setShippingAddressId</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">15243&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">setShippingTypeId</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">34251&nbsp;</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">//&nbsp;This&nbsp;causes&nbsp;$secondUser&nbsp;to&nbsp;publish&nbsp;in&nbsp;order&nbsp;to<br />//&nbsp;acquire&nbsp;a&nbsp;primary&nbsp;key&nbsp;because&nbsp;generatedOnPublish<br />//&nbsp;is&nbsp;set&nbsp;to&nbsp;true&nbsp;(meaning&nbsp;we&nbsp;can&nbsp;get&nbsp;this&nbsp;from&nbsp;the<br />//&nbsp;repository)&nbsp;for&nbsp;the&nbsp;related&nbsp;Column,&nbsp;and&nbsp;because<br />//&nbsp;the&nbsp;default&nbsp;Torpor&nbsp;configuration&nbsp;setting&nbsp;of<br />//&nbsp;PublishDependencies&nbsp;is&nbsp;also&nbsp;true.<br /></span><span style="color: #0000BB">$order</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">Publish</span><span style="color: #007700">();&nbsp;</span><span style="color: #FF8000">//&nbsp;Publishes&nbsp;$secondUser&nbsp;first.
</div>
</html>

[[TypedGrids|TypedGrid]] omit the need to make use of a {{{$torpor}}} instance directly, replacing the {{{new}}} and {{{...ById}}} commands with standard PHP constructor operations:

<html><span style="font-family: monospace;"><span style="color: #FF8000">//&nbsp;Identical&nbsp;to&nbsp;-&gt;getUserById(&nbsp;12345&nbsp;);<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">User</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">12345&nbsp;</span><span style="color: #007700">);<br /></span><span style="color: #FF8000">//&nbsp;Identical&nbsp;to&nbsp;-&gt;newUser()&nbsp;or&nbsp;-&gt;newUserSet();<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">User</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">UserSet</span><span style="color: #007700">();</span></span></html>

This is a fairly dense first example, but it should be noted that (assuming the {{{test}}} database specified exists according to the [[simple_sample.xml]] definition) this is all it takes to use Torpor: there is no code generation or series of includes or manual overhead; the factory pattern goes right to work dynamically typing instances of [[Grid]] objects to match the definitions and relating them to one another.

Previous: [[Features]]
Next: [[Configuration]] (or [[Examples]] if you're impatient)
Torpor is a persistence layer abstraction in PHP, providing a form of object-relational mapping derived from the design of the database (and encouraging good design principles). It is written entirely in PHP, and has been designed with ease of implementation and performance as primary goals. 
!!Objective
Torpor was created to perform all the legwork between the design of a database and the most common patterns of access and manipulation to it. This comes from several years of working with database abstractions in numerous languages and scopes of implementation, from simple one-off scripts up through major infrastructure for insurance, web hosting, and ecommerce retailers. In almost all cases, regardless of the tools in play, the ways in which data is accessed, combined, and published, follow very predictable patterns. There are [[dozens of projects|Alternatives]] in their respective languages which seek to encapsulate those patterns into common abstractions, each enforcing their own pragmatism on the implementation.

Torpor seeks to be lightweight and sufficiently logical that it plays well with developer needs, and is extensible and configurable enough that even if the defaults aren't perfectly suited it can still be adapted to stay out of the way (see [[Alternatives]] for a list of other comparable PHP ORM solutions you may want to consider as well).  It aims to be the shortest possible distance between idea and implementation without compromising on enterprise level features normally available only with considerable effort and expenditure of resources. These [[features|Features]] include automatic design and instantiation for data objects, implicit factories for related entities, updatable collections, data engine agnosticism, and performance options for just-in-time fetches, bulk loading, and distributed caching.  It should be the easiest way to work with native data and objects in PHP, and likewise on the reciprocal data storage interface.

In order to be useful to the PHP community this needed to be as simple to the end user as possible and compatible with established conventions rather than requiring entirely new or radically different theories or adaptations to be used. It should feel, if we have done our job right, like the best possible object interface that you would come up with were it all to be written manually and with painstaking care. Our focus on quality, best practices, and effective performance have been uncompromising, and [[feedback|Feedback]] for improvement is always welcome.
!!Concepts
Torpor works with data in tabular formats, but does not refer to them specifically as Tables in order to avoid confusion with database specific terminology, since the data repository may not actually be a database (in much the same way that ORM frameworks typically refer to the "persistence layer" to be generic). Instead, the term Grid is used.  This refers to the general definition of the Grid layout itself by representing a generic record structure from the same: the Grid is composed of the Columns common to every line item - in this way it refers to both the ovarching Grid design as a tabular entity and an instance record from the same.  Hopefully this isn't too confusing - it's mostly for convenience since there are no other components which describe the collected structure, and in practice should be fairly straightforward.

Heavy reliance is made on factory patterns, using one object as the gateway to the creation (or retrieval) of other related objects. It is possible to use the system more generically without relying on this behind the scenes magic, but there are some key benefits which make it worthwhile to adhere to (especially late-binding data relationships, keeping multiple object references in sync prior to publishing to the data store). 
!!Requirements
Torpor is written entirely in PHP and requires version 5.1.0 or greater, with the ~SimpleXML and DOM extensions, and support for the data engine of your choice. This target version was chosen in order to get the best overlap between capabilities and availability - some of the nicer conventions and features of later versions (such as name spaces and some dynamic execution mechanisms such as {{{__callStatic}}}) have been omitted in order to maintain this compatibility. As a result, all classes are declared in the global namespace and it is up to the end user to ensure collisions do not occur.
!!License
Torpor is offered under the [[MIT license|http://en.wikipedia.org/wiki/MIT_License]], which allows for inclusion in paid projects and unrestricted extension of the code so long as others are afforded the same rights. We would ask that any useful modification be propagated back to the project, and will even say "pretty please" - but you're otherwise completely unrestricted in the use and distribution of this software. 

Next: [[Features]]
[[Introduction]]
[[Features]]
[[Getting Started|Getting Started with Torpor]]
[[Configuration]]
[[Examples]]
[[Advanced Usage]]
[[Appendix]]

<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryDark]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<div class='footer' style='margin: 2em; clear: all; width: 50%; margin: 0px auto;'>
All content provided under the <a href="http://www.opensource.org/licenses/mit-license.php">MIT License</a>, without warranty or other restriction.  Use at your own risk, as you see fit, and allow others to do the same. // Visit us at the <a ref="http://code.google.com/p/torpor-php">Torpor home page</a>.
</div>
<!--}}}-->
Email: [[paul@paultomlinson.net|mailto:paul@paultomlinson.net]]
Home page: [[paultomlinson.net|http://paultomlinson.net]]
$Rev: 73 $
Use of [[caching|Config: Cache]] is highly recommended, keeping referenced data close to the point of utilization to shorten subsequent lookups after an initial load.  PHP Sessions are a very convenient way of doing that for one thread at a time, and while this is not as useful (or safe) as doing a distributed cache it's still better than nothing.

PHP Sessions allow for the caching of complex objects, provided that the definition of the object can be located before it is deserialized back onto the stack.  However, Torpor objects are highly contextual and thus potentially very large: a {{{Grid}}} object refers not only to its {{{Column}}} data members, but also the {{{Torpor}}} instance (singleton or otherwise) which is its connection to the repository.  The {{{Torpor}}} instance in turn maintains references to its parsed configuration, repository connections, cache instances, etc.; thus attempting to store a {{{Grid}}} in the session a difficult proposition where referential and connective integrity are messy if not impossible and therefor not recommended.

There are a few options to help overcome these limitations.  The first is the use of one of the provided caching mechanisms, which save only the relevant details from a loaded (and that "loaded" part is essential) {{{Grid}}} instance.  This has a slight limitation however in that it only acts as an intermediate cache from the {{{DataStore}}} adapter and the repository, and will only return the data when it's requested by an exact key - which means the key must still be stored locally.  This isn't ''too'' unwieldy, but does require an extra step:

<html><span style="font-family: monospace;"><span style="color: #FF8000">//&nbsp;Torpor&nbsp;Instance&nbsp;Access<br /></span><span style="color: #0000BB">$current_user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getUserById</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$_SESSION</span><span style="color: #007700">[</span><span style="color: #DD0000">'current_user.id'</span><span style="color: #007700">]&nbsp;);<br /><br /></span><span style="color: #FF8000">//&nbsp;TypedCrid&nbsp;access<br /></span><span style="color: #0000BB">$current_user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">User</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$_SESSION</span><span style="color: #007700">[</span><span style="color: #DD0000">'current_user.id'</span><span style="color: #007700">]&nbsp;);</span></span></span></html>

Again, this only applies to loaded {{{Grid}}} instances which can retrieve that object from Torpor's cache.

For working with partial {{{Grid}}} data (user-populated or not fully loaded) or otherwise serializing the content of a {{{Grid}}}, there are a few built-in methods that may prove useful:
* ''{{{Grid::dumpArray}}}:'' returns an associative array with Torpor style key names for each {{{Column}}} and the data of the corresponding {{{Column}}} member.  This will implicitly load the {{{Grid}}} if it can be and has not already been.
* ''{{{Grid::dumpObject}}}:'' same as {{{dumpArray}}}, but returns the contents as a PHP {{{stdClass}}} object instead.
* ''{{{Grid::LoadFromArray}}}:'' takes an associative array argument and populates all of the {{{Column}}} members of the {{{Grid}}} with corresponding data.  A second optional ''boolean'' argument will determine whether or not the {{{Grid}}} is marked as having been loaded as well; however, if there is //not// a corresponding repository record this should not be set to ''true'' (defaults to ''false'').
* ''{{{Grid::LoadFromObject}}}:'' sames as {{{LoadFromArray}}}, but takes a PHP {{{stdClass}}} object as the first argument instead of an associative array.

A word of caution: all standard constraints and conventions apply to loading data via this mechanisms as doing regular data assignment.  That is, a {{{NULL}}} data value passed to a {{{Column}}} that is marked as non-nullable //will// throw an exception.  This is an especial problem in this area because a {{{Grid}}} that has not loaded will have {{{NULL}}} data members unless those members have a ''default'' value specified in the configuration.  This means it's possible to pass from {{{Grid::dumpArray}}} straight into {{{Grid::LoadFromArray}}} and counter-intuitively produce an exception.  The best workaround for this, other then ensuring that all {{{Grid}}} objects are loaded, is to leverage the optional arguments on the {{{dump<...>}}} methods:
# {{{boolean }}}//{{{$all}}}//: defaults to ''true'', returns all {{{Column}}} members even if they do no {{{hasData}}}.  If set to ''false'', only those {{{Column}}} objects which have been explicitly populated will be returned.
# {{{boolean }}}//{{{$load}}}//: defaults to ''true'', determines whether or not an implicit {{{Load}}} attempt will be made (assuming {{{Grid::canLoad()}}}) prior to returning results.  If set to ''false'' only the current contents will be returned.

For more details see the {{{Grid}}} [[class reference|Class: Grid]].

If any of these options will be used with any frequency it's recommended to create some intelligent wrappers or possibly even override the default session handler to be able to handle {{{Grid}}} instances intelligently.

Up: [[Advanced Usage]]
Previous: [[Extension]]
Next: [[Typed Grids|TypedGrid]]
release 1.0 Documentation and Usage Guide
Torpor
.tiddler { border: 1px solid [[ColorPalette::TertiaryLight]]; margin-bottom: 1em; padding-bottom: 0.5em; }
.footer { color: [[ColorPalette::TertiaryMid]]; text-align: center; }
| !Repository Type | !Repository Version | !Torpor Name* | !Torpor Version | !Torpor Class(.php) |h
| ~MySQL | 5.0+ | ~MySQL | 1.0 | [[MySQLDataStore|Class: MySQLDataStore]] |
|~|~| ~MySQLi | //future// | -- |
| Postgres | -- | Postgres | 1.0.x (> 1.0) | -- |
| ODBC | -- | ODBC | //future// | -- |
| Oracle | 10g+ | Oracle<br/>OCI | 1.0 | [[OracleDataStore|Class: OracleDataStore]] |
| ~SQLite | 3 | ~SQLite | 1.0 | [[SQLiteDataStore|Class: SQLiteDataStore]] |
| SQL Server | 2005+ | ~SQLServer<br/>MSSQL | 1.0 | [[MSSQLDataStore|Class: MSSQLDataStore]] |
 *Names are case-insensitive in XML settings.
Use of the {{{TypedGridClasses}}} [[option|Config: Options]] creates once class for every {{{Grid}}} defined in the configuration, as an extension of the built-in {{{TypedGrid}}} class (the resulting class name may optionally have a prefix as specified by the {{{TypedGridClassesPrefix}}} option), which itself is an extension to the {{{Grid}}} class and therefore supports all the same members, interfaces, and features.  This dynamic class creation allows for "typing" or type-hinting of each of the {{{Grid}}} instances to a more specific class qualifier than "Grid," as well as for factory-independent instantiation in singleton mode (technically it's also possible to use this pattern in instance mode, but only by passing a {{{Torpor}}} instance as an argument to every new object's constructor which can become unmaintainable rather quickly).

<html><span style="font-family: monospace;"><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;new&nbsp;</span><span style="color: #0000BB">User</span><span style="color: #007700">();<br /></span><span style="color: #FF8000">//&nbsp;instead&nbsp;of...<br /></span><span style="color: #0000BB">$user&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$MyTorpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">newUser</span><span style="color: #007700">();</span></span></html>

Which also allows for class verification and hints:
<html><span style="font-family: monospace;"><span style="color: #007700">if(&nbsp;</span><span style="color: #0000BB">$obj&nbsp;</span><span style="color: #007700">instanceof&nbsp;</span><span style="color: #0000BB">User&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}<br />function&nbsp;</span><span style="color: #0000BB">handleUser</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">User&nbsp;$user&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #FF8000">/*&nbsp;...&nbsp;*/<br /></span><span style="color: #007700">}</span></span></html>
...etc.

The real genius of all of this is that these classes (and corresponding {{{TypedGridSet}}} classes) are created on-the-fly by Torpor as required.  There are a few exercises required to initially set up this functionality, after which modification and extension are extremely straightforward.

Using this option there is no need to set the {{{class}}} attribute of each {{{Grid}}} in the configuration; a correspondingly named class is automatic.  Use of {{{TypedGrid}}s and other extensions to {{{Grid}}} at the same time is not recommended or supported, and may produce unexpected errors.
!Autoload
The first requirement is to turn on {{{TypedGridClasses}}} in the [[configuration|Config: Options]] by setting the value to ''true''.  The {{{TypedGridClassesPrefix}}} may optionally be used to provide a character prefix which will be added to each of the class names (e.g., a {{{TypedGridClassesPrefix}}} of "{{{Torpor}}}" and a {{{Grid}}} with a {{{name}}}/{{{dataname}}} value of "{{{User}}}" would result in a class of "{{{TorporUser}}}").  The second requirement is to place the automatic validation/class creation routine into the PHP magic {{{__autoload}}} function (see the [[PHP documentation|http://php.net/manual/en/language.oop5.autoload.php]] for in-depth information).  It is recommended to place Torpor's call as the very last of the process in order to allow for easier extension, which will be explored below.  An example of this would be:

<html><span style="font-family: monospace;"><span style="color: #007700">function&nbsp;</span><span style="color: #0000BB">__autoload</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$className&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$classesDirectories&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">explode</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">PATH_SEPARATOR</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">get_include_path</span><span style="color: #007700">()&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$classesDirectories</span><span style="color: #007700">[]&nbsp;=&nbsp;</span><span style="color: #DD0000">'/some/custom/library/path'</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$found&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">false</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;foreach(&nbsp;</span><span style="color: #0000BB">$classesDirectories&nbsp;</span><span style="color: #007700">as&nbsp;</span><span style="color: #0000BB">$classesDirectory&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pathToClassFile&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">$classesDirectory</span><span style="color: #007700">.</span><span style="color: #DD0000">'/'</span><span style="color: #007700">.</span><span style="color: #0000BB">$className</span><span style="color: #007700">.</span><span style="color: #DD0000">'.php'</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;</span><span style="color: #0000BB">file_exists</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pathToClassFile&nbsp;</span><span style="color: #007700">)&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;require_once(&nbsp;</span><span style="color: #0000BB">$pathToClassFile&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$found&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">true</span><span style="color: #007700">;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;!</span><span style="color: #0000BB">$found&nbsp;</span><span style="color: #007700">){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$torpor&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #0000BB">Torpor</span><span style="color: #007700">::</span><span style="color: #0000BB">getInstance</span><span style="color: #007700">();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;!</span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">isInitialized</span><span style="color: #007700">()&nbsp;){<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">initialize</span><span style="color: #007700">(&nbsp;</span><span style="color: #DD0000">'MyCustomConfig.xml'&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$torpor</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">typedGridClassCheck</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$className&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></span></html>

This example assumes that any requested class name not already defined will either have a file corresponding to the class name (special consideration must be taken on case-sensitive file systems) with a '.php' extension either in the include path or in a custom library path, or will be defined by Torpor via the {{{typedGridClassCheck}}} method on a singleton instance.  If the configuration file is named {{{TorporConfig.xml}}} and exists in PHP include path, the only required line would be {{{Torpor::typedGridClassCheck( $className );}}}, which would implicitly acquire the singleton, conditionally initialize it, and then perform the class check.

The {{{typedGridClassCheck}}} method looks at the configuration, determines whether or not the requested class name matches any of the defined {{{Grid}}} entities (including any prefix), and if not, defines the class as extending {{{TypedGrid}}} with no other options or customizations.  The same process is used for {{{TypedGridSet}}} instances, which are accessed by appending {{{Set}}} to the class name.

Using this process, no class exists until it is first requested, either by direct instantiation or through factory methods on another class or set.
!Instantiation
Each {{{TypedGrid}}} accepts 2 kinds of arguments to the constructor, both optional.
# A {{{Torpor}}} instance to use instead of the implicit singleton acquisition.
# One or more values to automatically assign as members of the [[primary key|Config: Keys: Primary]] after the instance has been created.  For multiple-column keys these arguments should be passed in the order that the key is defined in the configuration.  Assuming they key population is complete and corresponds with known records in the repository, the object will then be capable of loading as if it had been created via {{{Torpor::get<Object>ById()}}}.

Instances can be created through use of the {{{new}}} keyword just as with other PHP objects, or through all of the same factory methods and relationships already explored in the [[related objects|Examples: Related Objects]] examples.

Note: as with other related objects, the use of any prefix (via the {{{TypedGridClassesPrefix}}} configuration option) does not alter the invocation of related object syntax.  A {{{Grid}}} with a {{{name}}}/{{{dataname}}} of {{{User}}}, even if given a {{{My}}} prefix to result in {{{MyUser}}}, will still require use of {{{$order->getUser()}}} syntax rather than {{{$order->getMyUser()}}}.

!Extension
The evaluated PHP code used by Torpor for creating each named {{{Grid}}} class is extremely simple:
<html><span style="font-family: monospace;"><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">User&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">TypedGrid&nbsp;</span><span style="color: #007700">{}</span></span></html>

The guts of the {{{TypedGrid}}} class being extended are responsible for using the class name in conjunction with the {{{Torpor}}} instance to determine what type of {{{Grid}}} it is during construction, and sets up all of its internals and data members during that time by working with that instance.

It is possible and highly recommended for an implementing developer to use this same extension, and even the same class names, in order to specify customizations.  Re-writing the {{{User}}} class [[extension|Extension]] example for use with {{{TypedGrid}}}s simply requires changing the word {{{Grid}}} to {{{TypedGrid}}} in the name definition:

<html><span style="font-family: monospace;"><span style="color: #007700">class&nbsp;</span><span style="color: #0000BB">User&nbsp;</span><span style="color: #007700">extends&nbsp;</span><span style="color: #0000BB">TypedGrid<br /></span><span style="color: #007700">{<br />&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;</span><span style="color: #0000BB">MD5_REGEX&nbsp;</span><span style="color: #007700">=&nbsp;</span><span style="color: #DD0000">'/^[A-Fa-f0-9]{32}$/'</span><span style="color: #007700">;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;function&nbsp;</span><span style="color: #0000BB">passwordMatch</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw1</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;!</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">MD5_REGEX</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">)&nbsp;?&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">)&nbsp;:&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">=&nbsp;(&nbsp;!</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">MD5_REGEX</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)&nbsp;?&nbsp;</span><span style="color: #0000BB">md5</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">)&nbsp;:&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$pw1&nbsp;</span><span style="color: #007700">==&nbsp;</span><span style="color: #0000BB">$pw2&nbsp;</span><span style="color: #007700">);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;function&nbsp;</span><span style="color: #0000BB">isUserPassword</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$password&nbsp;</span><span style="color: #007700">)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">passwordMatch</span><span style="color: #007700">(&nbsp;</span><span style="color: #0000BB">$password</span><span style="color: #007700">,&nbsp;</span><span style="color: #0000BB">$this</span><span style="color: #007700">-&gt;</span><span style="color: #0000BB">getPassword</span><span style="color: #007700">()&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</span></span></html>

So long as this code is evaluated before the {{{typedGridClassCheck}}} method is invoked, this definition will stand and be used in all the same ways and places.  Same goes for extensions to {{{TypedGridSet}}}.

The constructor should not be overridden unless the call is still included in the new constructor method via a {{{parent::__construct()}}} call, propagating any arguments as appropriate.  However, the {{{OnNew()}}} method will also be invoked at the end of construction and assignment of any initial value assignment (those arguments passed to the constructor), making that a recommended avenue for managing instantiation and initialization.

One final caveat for manual extension of the {{{TypedGrid}}} class: the object automatically associates with the singleton {{{Torpor}}} instance unless one is provided to the constructor, as previously discussed.  In the {{{__autoload}}} example above, the singleton is initialized using a custom configuration (something other than "~TorporConfig.xml" available in the PHP include path) when a {{{TypedGrid}}} object is being created.  However, if that class definition has been provided via other means, either the {{{typedGridClassCheck}}} method will be bypassed, along with the initialization block (which is easy enough to compensate for by moving the initialization earlier in the {{{__autoload}}} function), or the entirety of {{{__autoload}}} will be bypassed because the class definition is already a part of the operating environment.

If this happens it's possible that the class will attempt to derive its {{{Grid}}} affiliation and data members from an uninitialized {{{Torpor}}} instance, failing noisily.  As a workaround it is recommended to either absolutely ensure that the singleton has already been initialized through a common means guaranteed to execute beforehand, or by setting the {{{TORPOR_CONFIG}}} environment variable to indicate the location (via file or URI) of the desired configuration which will override the default "~TorporConfig.xml" - or you can just name your configuration file according to the default and all is well that way too.

Up: [[Advanced Usage]]
Previous: [[Sessions]]
Next: [[Appendix]]
<html>
<div style="background-color: #FFF; font-family: monospace; whitespace:nowrap;">
<font color="#5555CC">&lt;?</font><font color="#009900">xml</font><font color="#009900">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">'1.0'</font><font color="#5555CC">?&gt;</font><br>
<font color="#5555CC">&lt;</font><font color="#CC20CC">trpr</font><font color="#5555CC">:</font><font color="#5555CC">TorporConfig</font><font color="#5555CC">&nbsp;</font><font color="#009900">version</font>=<font color="#990000">&quot;0.1&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">xmlns</font><font color="#5555CC">:</font><font color="#009900">trpr</font>=<font color="#990000">&quot;<a href="http://www.tricornersoftware.com/Products/Torpor/Config/0.1">http://www.tricornersoftware.com/Products/Torpor/Config/0.1</a>&quot;</font><font color="#5555CC">&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Repository</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">DataStore</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;MySQL&quot;</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;username&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">value</font>=<font color="#990000">&quot;test&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Parameter</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;database&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">value</font>=<font color="#990000">&quot;test&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/DataStore&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Repository&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Grids</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;USERS&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;USER_ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;ReferringUserId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;REFERRING_USER_ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;USER_NAME&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;255&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Email&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;EMAIL_ADDRESS&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;255&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;PasswordHash&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;PASSWORD&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;varchar&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">class</font>=<font color="#990000">&quot;PasswordHash&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">length</font>=<font color="#990000">&quot;32&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Foreign</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;ReferringUserId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGridAlias</font>=<font color="#990000">&quot;ReferringUser&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceColumn</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Foreign&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserName&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Email&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Grid&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Grid</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Order&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;ORDERS&quot;</font><font color="#5555CC">&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Columns</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;ORDER_ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">generatedOnPublish</font>=<font color="#990000">&quot;true&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;UserId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;USER_ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;SellerId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;SELLER_ID&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;Date&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;ORDER_DATE&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;datetime&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;ShippingAddressId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;SHIPPING_ADDRESS&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Column</font><font color="#5555CC">&nbsp;</font><font color="#009900">name</font>=<font color="#990000">&quot;ShippingTypeId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">dataName</font>=<font color="#990000">&quot;SHIPPING_TYPE&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">type</font>=<font color="#990000">&quot;unsigned&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Columns&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Keys</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Foreign</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceColumn</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;SellerId&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGrid</font>=<font color="#990000">&quot;User&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceGridAlias</font>=<font color="#990000">&quot;Seller&quot;</font><font color="#5555CC">&nbsp;</font><font color="#009900">referenceColumn</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Foreign&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Primary</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Id&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Primary&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Unique</font><font color="#5555CC">&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;UserId&quot;</font><font color="#5555CC">/&gt;</font><br>

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;</font><font color="#5555CC">Key</font><font color="#5555CC">&nbsp;</font><font color="#009900">column</font>=<font color="#990000">&quot;Date&quot;</font><font color="#5555CC">/&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Unique&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Keys&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Grid&gt;</font><br>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#5555CC">&lt;/Grids&gt;</font><br>
<font color="#5555CC">&lt;/</font><font color="#CC20CC">trpr</font><font color="#5555CC">:</font><font color="#5555CC">TorporConfig&gt;</font><br>
</div>
</html>