CC-2166: Packaging Improvements. Moved the Zend app into airtime_mvc. It is now installed to /var/www/airtime. Storage is now set to /srv/airtime/stor. Utils are now installed to /usr/lib/airtime/utils/. Added install/airtime-dircheck.php as a simple test to see if everything is install/uninstalled correctly.

This commit is contained in:
Paul Baranowski 2011-04-14 18:55:04 -04:00
parent 514777e8d2
commit b11cbd8159
4546 changed files with 138 additions and 51 deletions

View file

@ -0,0 +1,381 @@
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!--
DB Designer XML to Propel Schema XML
==== Author: Jonathan Graham <jkgraham@gmail.com>
==== Version: 0.5 (2008-01-25) (http://blog.tooleshed.com/?p=6)
==== Description:
This XSL will transform a DB Designer 4 database model XML file into a
Propel database schema file. This allows you to design your database
model using DB Designer 4 (models are saved in XML format) and then
easily create the Propel database schema file.
The PROPEL properties that this XSL will translate are listed below.
TABLE: name, description
COLUMN: name, primaryKey, required, type, size, scale, default, autoIncrement, description
FOREIGN-KEY: foreignTable, name, onDelete
REFERENCE: local, foreign
INDEX: index (not related to FK), unique, fulltext
==== Usage:
- Simply feed this XSL into your favorite XSLT engine along with your DB Designer
XML model. The resulting output is a Propel database schema XML.
==== Collaboration:
Peter Banik <peter@froggle.org> - UNIQUE TAG
Benedicto Franco Jr. - MULTIPLE FOREIGN KEY, DATABASE NAME
Martin Kreidenweis <martin@kreidenweis.com> - Bug fixes, INDEX
Michiel Hakvoort - onDelete
Michel D'HOOGE - FULLTEXT
Oleg Marchuk <kingoleg@mail.ru> - version 0.5
==== Software:
Propel: http://propel.phpdb.org/
DB Designer 4: http://www.fabforce.net/dbdesigner4/
==== Copyright (c) 2004-2006, Jonathan Graham
Licensed under the GNU Lesser General Public License (LGPL) - http://www.gnu.org/copyleft/lgpl.html.
==== Change Log
version 0.1 (2004-11-08) - initial version
version 0.2 (2006-10-18) - Added Peter and Benedicto's updates.
version 0.3 (2006-11-05) - added non-unique-INDEXes and onDelete
version 0.4 (2006-11-13) - added support for index names and FULLTEXT indexes, changed license to LGPL
version 0.5 (2008-01-25) - added ENUM, GEOMETRY as BLOB, scale for DECIMAL; fixed size in ENUM and spaces in relation names
-->
<!-- ============================================================ DATABASE template -->
<xsl:template match="/">
<database defaultIdMethod="native">
<xsl:attribute name="name">
<xsl:value-of select="/DBMODEL/SETTINGS/GLOBALSETTINGS/@ModelName"/>
</xsl:attribute>
<xsl:apply-templates />
</database>
</xsl:template>
<!-- ============================================================ TABLES template -->
<xsl:template match="/DBMODEL/METADATA/TABLES/TABLE">
<table>
<xsl:attribute name="name">
<xsl:value-of select="@Tablename"/>
</xsl:attribute>
<xsl:if test="@Comments != ''">
<xsl:attribute name="description">
<xsl:value-of select="@Comments" />
</xsl:attribute>
</xsl:if>
<xsl:apply-templates />
</table>
</xsl:template>
<!-- ============================================================ COLUMNS template -->
<xsl:template match="COLUMNS/COLUMN">
<column>
<!-- get data type -->
<xsl:variable name="datatype">
<xsl:call-template name="get_datatype">
<xsl:with-param name="id"><xsl:value-of select="@idDatatype"/></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<!-- remove parens from datatypeparams -->
<xsl:variable name="dtpclean">
<xsl:call-template name="clean_dataparams">
<xsl:with-param name="dtp"><xsl:value-of select="@DatatypeParams"/></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<!-- ==== name ==== -->
<xsl:attribute name="name">
<xsl:value-of select="@ColName"/>
</xsl:attribute>
<!-- ==== type ==== -->
<xsl:attribute name="type">
<xsl:choose>
<xsl:when test="$datatype = 'ENUM'">
<xsl:value-of select="'CHAR'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$datatype"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="$dtpclean != ''">
<!-- ==== size ==== -->
<xsl:attribute name="size">
<xsl:call-template name="get_datasize">
<xsl:with-param name="dtpc"><xsl:value-of select="$dtpclean"/></xsl:with-param>
<xsl:with-param name="dtype"><xsl:value-of select="$datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:if test="contains('FLOAT,DOUBLE,DECIMAL',$datatype)">
<!-- ==== scale ==== -->
<xsl:attribute name="scale">
<xsl:value-of select="substring-after($dtpclean,',')"/>
</xsl:attribute>
</xsl:if>
</xsl:if>
<!-- ==== primaryKey ==== -->
<xsl:if test="@PrimaryKey = '1'">
<xsl:attribute name="primaryKey">true</xsl:attribute>
</xsl:if>
<!-- ==== required ==== -->
<xsl:if test="@NotNull = '1'">
<xsl:attribute name="required">true</xsl:attribute>
</xsl:if>
<!-- ==== default ==== -->
<xsl:if test="@DefaultValue != ''">
<xsl:attribute name="default">
<xsl:value-of select="@DefaultValue"/>
</xsl:attribute>
</xsl:if>
<!-- ==== autoIncrement ==== -->
<xsl:if test="@AutoInc = '1'">
<xsl:attribute name="autoIncrement">true</xsl:attribute>
</xsl:if>
<!-- ==== description ==== -->
<xsl:if test="@Comments != ''">
<xsl:attribute name="description">
<xsl:value-of select="@Comments"/>
</xsl:attribute>
</xsl:if>
</column>
</xsl:template>
<!-- ============================================================ RELATIONS template -->
<xsl:template match="RELATIONS_END/RELATION_END">
<xsl:variable name="id"><xsl:value-of select="@ID"/></xsl:variable>
<xsl:call-template name="show_ForeignKey">
<xsl:with-param name="relation" select="/DBMODEL/METADATA/RELATIONS/RELATION[@ID=$id]"/>
</xsl:call-template>
</xsl:template>
<!-- ============================================================ INDEX template -->
<xsl:template match="INDICES/INDEX">
<xsl:choose>
<xsl:when test="@IndexKind = '1' and @FKRefDef_Obj_id='-1'">
<index>
<xsl:attribute name="name"><xsl:value-of select="@IndexName"/></xsl:attribute>
<xsl:apply-templates select="INDEXCOLUMNS/INDEXCOLUMN" mode="normal"/>
</index>
</xsl:when>
<xsl:when test="@IndexKind = '2'">
<unique>
<xsl:attribute name="name"><xsl:value-of select="@IndexName"/></xsl:attribute>
<xsl:apply-templates select="INDEXCOLUMNS/INDEXCOLUMN" mode="unique"/>
</unique>
</xsl:when>
<xsl:when test="@IndexKind = '3'">
<index>
<xsl:attribute name="name"><xsl:value-of select="@IndexName"/></xsl:attribute>
<xsl:apply-templates select="INDEXCOLUMNS/INDEXCOLUMN" mode="normal"/>
<vendor type="mysql">
<parameter name="Index_type" value="FULLTEXT"/>
</vendor>
</index>
</xsl:when>
</xsl:choose>
</xsl:template>
<!-- ============================================================ columns within an index -->
<xsl:template match="INDICES/INDEX/INDEXCOLUMNS/INDEXCOLUMN" mode="normal">
<xsl:variable name="columnId"><xsl:value-of select="@idColumn"/></xsl:variable>
<index-column>
<xsl:attribute name="name"><xsl:value-of select="//COLUMNS/COLUMN[@ID=$columnId]/@ColName"/></xsl:attribute>
</index-column>
</xsl:template>
<xsl:template match="INDICES/INDEX/INDEXCOLUMNS/INDEXCOLUMN" mode="unique">
<xsl:variable name="columnId"><xsl:value-of select="@idColumn"/></xsl:variable>
<unique-column>
<xsl:attribute name="name"><xsl:value-of select="//COLUMNS/COLUMN[@ID=$columnId]/@ColName"/></xsl:attribute>
</unique-column>
</xsl:template>
<!-- ============================================================ show_ForeignKey -->
<xsl:template name="show_ForeignKey">
<xsl:param name="relation"/>
<foreign-key>
<!-- foreignTable -->
<xsl:attribute name="foreignTable">
<xsl:value-of select="/DBMODEL/METADATA/TABLES/TABLE[@ID=$relation/@SrcTable]/@Tablename"/>
</xsl:attribute>
<!-- name -->
<xsl:attribute name="name">
<xsl:value-of select="translate($relation/@RelationName, ' ', '_')"/>
</xsl:attribute>
<!-- onDelete -->
<xsl:attribute name="onDelete">
<xsl:variable name="actionId">
<xsl:call-template name="str_replace">
<xsl:with-param name="stringIn" select="substring-before(substring-after($relation/@RefDef,'\n'), '\n')"/>
<xsl:with-param name="charsIn" select="'OnDelete='"/>
<xsl:with-param name="charsOut" select="''"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="get_actiontype">
<xsl:with-param name="id" select="$actionId" />
</xsl:call-template>
</xsl:attribute>
<!-- === reference tag === -->
<xsl:call-template name="build_fk">
<xsl:with-param name="stringIn" select="$relation/@FKFields"/>
</xsl:call-template>
</foreign-key>
</xsl:template>
<!--
============================================================
============================================================ template "functions"
============================================================
-->
<!-- ============================================================ get_datatype -->
<xsl:template name="get_datatype">
<xsl:param name="id"/>
<xsl:variable name="type">
<xsl:value-of select="/DBMODEL/SETTINGS/DATATYPES/DATATYPE[@ID=$id]/@TypeName"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$type = 'DATETIME'" >TIMESTAMP</xsl:when>
<xsl:when test="$type = 'TEXT'" >LONGVARCHAR</xsl:when>
<xsl:when test="$type = 'BOOL'" >BOOLEAN</xsl:when>
<xsl:when test="$type = 'GEOMETRY'" >BLOB</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$type"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- ============================================================ get_datasize -->
<xsl:template name="get_datasize">
<xsl:param name="dtpc"/>
<xsl:param name="dtype"/>
<xsl:choose>
<xsl:when test="contains('FLOAT,DOUBLE,DECIMAL',$dtype)" >
<xsl:value-of select="substring-before($dtpc,',')"/>
</xsl:when>
<xsl:when test="$dtype = 'ENUM'">
<xsl:value-of select="''" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$dtpc"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- ============================================================ clean_dataparams -->
<xsl:template name="clean_dataparams">
<xsl:param name="dtp"/>
<xsl:variable name="dtp2">
<xsl:call-template name="str_replace">
<xsl:with-param name="stringIn" select="$dtp"/>
<xsl:with-param name="charsIn" select="'('"/>
<xsl:with-param name="charsOut" select="''"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="str_replace">
<xsl:with-param name="stringIn" select="$dtp2"/>
<xsl:with-param name="charsIn" select="')'"/>
<xsl:with-param name="charsOut" select="''"/>
</xsl:call-template>
</xsl:template>
<!-- ============================================================ str_replace -->
<xsl:template name="str_replace">
<xsl:param name="stringIn"/>
<xsl:param name="charsIn"/>
<xsl:param name="charsOut"/>
<xsl:choose>
<xsl:when test="contains($stringIn,$charsIn)">
<xsl:value-of select="concat(substring-before($stringIn,$charsIn),$charsOut)"/>
<xsl:call-template name="str_replace">
<xsl:with-param name="stringIn" select="substring-after($stringIn,$charsIn)"/>
<xsl:with-param name="charsIn" select="$charsIn"/>
<xsl:with-param name="charsOut" select="$charsOut"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$stringIn"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- ============================================================== build_fk -->
<xsl:template name="build_fk">
<xsl:param name="stringIn"/>
<xsl:variable name="FKClean">
<xsl:value-of select="substring-before($stringIn, '\n')"/>
</xsl:variable>
<reference>
<xsl:attribute name="local">
<xsl:value-of select="substring-after($FKClean, '=')"/>
</xsl:attribute>
<xsl:attribute name="foreign">
<xsl:value-of select="substring-before($FKClean, '=')"/>
</xsl:attribute>
</reference>
<xsl:if test="contains(substring-after($stringIn,'\n'),'=')">
<xsl:call-template name="build_fk">
<xsl:with-param name="stringIn" select="substring-after($stringIn,'\n')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<!-- ======================================================== get_actiontype -->
<xsl:template name="get_actiontype">
<xsl:param name="id"/>
<xsl:choose>
<xsl:when test="$id = 0">restrict</xsl:when>
<xsl:when test="$id = 1">cascade</xsl:when>
<xsl:when test="$id = 2">setnull</xsl:when>
<xsl:otherwise>restrict</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View file

@ -0,0 +1,21 @@
<?php
/*
This PHP5 script will load the transform a DB Designer 4 database model to the
propel database schema file format
*/
// load the DB Designer 4 XML
$xml = new DOMDocument;
$xml->load('model.xml');
// load the transformation stylesheet
$xsl = new DOMDocument;
$xsl->load('dbd2propel.xsl');
$proc = new XSLTProcessor();
// attach the xsl rules
$proc->importStyleSheet($xsl);
$schema_xml = $proc->transformToXML($xml);
file_put_contents('schema.xml', $schema_xml);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
<?php
class patForms_Creator_Definition {
static function create($definition, $object = null) {
$form = patForms::createForm(null, array(
'name' => $definition->name
));
foreach ($definition->elements as $el) {
$element = &$form->createElement($el['name'], $el['type'], null);
if (!empty($el['attributes']['datasource'])) {
$ds = $el['attributes']['datasource'];
unset($el['attributes']['datasource']);
$element->setDatasource(new $ds['name']($ds));
}
// patForms will choke when we try to set attributes that
// don't exist for an element type. So we'll have to ask.
foreach ($el['attributes'] as $name => $value) {
if ($element->hasAttribute($name)) {
$element->setAttribute($name, $value);
}
}
if (isset($el['rules'])) {
foreach ($el['rules'] as $rule) {
$element->addRule(new $rule['type']($rule));
}
}
$form->addElement($element);
}
if (!is_null($object)) {
$form->setValues($object->toArray());
}
if ($definition->autoValidate) {
$form->setAutoValidate($definition->autoValidate);
}
return $form;
}
}

View file

@ -0,0 +1,132 @@
<?php
/**
* patForms Creator Propel
*
* @package patForms
* @subpackage Creator
*/
/**
* Error: could not connect to the database
*/
define( 'PATFORMS_CREATOR_PROPEL_ERROR_NO_CONNECTION', 'patForms:Creator:Propel:01' );
/**
* patForms Creator DB
*
* @access protected
* @package patForms
* @subpackage Creator
* @author Bert Van den Brande <cyruzb@gmail.com>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Creator_Propel extends patForms_Creator
{
private static $creoleTypeMapping = array(
CreoleTypes::BOOLEAN =>'Radio', // BOOLEAN = 1;
CreoleTypes::BIGINT =>'String', // BIGINT = 2;
CreoleTypes::SMALLINT =>'String', // SMALLINT = 3;
CreoleTypes::TINYINT =>'String', // TINYINT = 4;
CreoleTypes::INTEGER =>'String', // INTEGER = 5;
CreoleTypes::CHAR =>'String', // CHAR = 6;
CreoleTypes::VARCHAR =>'String', // VARCHAR = 7;
CreoleTypes::FLOAT =>'String', // FLOAT = 8;
CreoleTypes::DOUBLE =>'String', // DOUBLE = 9;
CreoleTypes::DATE =>'Date', // DATE = 10;
CreoleTypes::TIME =>'String', // TIME = 11;
CreoleTypes::TIMESTAMP =>'Date', // TIMESTAMP = 12;
CreoleTypes::VARBINARY =>'String', // VARBINARY = 13;
CreoleTypes::NUMERIC =>'String', // NUMERIC = 14;
CreoleTypes::BLOB =>'String', // BLOB = 15;
CreoleTypes::CLOB =>'String', // CLOB = 16;
CreoleTypes::TEXT =>'Text', // TEXT = 17;
CreoleTypes::LONGVARCHAR =>'Text', // LONGVARCHAR = 17;
CreoleTypes::DECIMAL =>'String', // DECIMAL = 18;
CreoleTypes::REAL =>'String', // REAL = 19;
CreoleTypes::BINARY =>'String', // BINARY = 20;
CreoleTypes::LONGVARBINARY =>'String', // LONGVARBINARY = 21;
CreoleTypes::YEAR =>'String', // YEAR = 22;
CreoleTypes::ARR =>'String',
CreoleTypes::OTHER =>'String'
);
/**
* Create a form from a propel instance
*
* @access public
* @param mixed $object An instance of a Propel object
* @param array $options Any options the creator may need
* @return object $form The patForms object, or a patError object on failure.
*/
function &create( $object, $options = array() )
{
// Propel stuff
$propel_peer = $object->getPeer();
$propel_mapBuilder = $propel_peer->getMapBuilder(); // Not sure if we're gonna need this one
$propel_tablename = constant(get_class($propel_peer) . '::TABLE_NAME');
$propel_tableMap = $propel_mapBuilder->getDatabaseMap()->getTable($propel_tablename);
// The form
$form =& patForms::createForm( null, array( 'name' => 'patForms_Creator_Form' ) );
$propel_cols = $propel_tableMap->getColumns();
foreach ($propel_cols as $propel_colname => $propel_col) {
// phpName can be altered by editing the schema.xml,
// thus I think, we should lowercase()/ucfirst() this
$propel_colname = strtolower($propel_colname);
$el_displayname = ucFirst($propel_colname);
// this could be omitted of course, but I think, it's a
// convenient way to get more safe request properties
$el_name = $propel_tablename . '[' . $propel_colname . ']';
$el_attr = array(
'edit' => 'yes',
'title' => $el_displayname,
'label' => $el_displayname,
'name' => $el_name,
'description' => $el_displayname
);
//// Obsolete ?
// Parse column info to element type info
//$type_info = $this->parseTypeInfoFromColumn($propel_col);
// Merge extra element attributes
//$el_attr = array_merge( $el_attr, $type_info['attributes'] );
// Is the element required ? Can we retrieve this info from the Column object ?
$el_attr['required'] = 'yes';
// Value: for now we use default to set the value. Is there a better (more correct) way to do this ?
$el_attr['default'] = $object->{'get'.$propel_col->getPhpName()}();
if ($propel_col->isPrimaryKey()) {
$el_type = 'hidden';
} else {
$el_type = self::$creoleTypeMapping[$propel_col->getCreoleType()];
}
$el = &$form->createElement($el_name, $el_type, null);
// patForms will choke when we try to set attributes
// that don't match the element type. So we'll ask.
foreach ($el_attr as $name => $value) {
if ($el->hasAttribute($name)) {
$el->setAttribute($name, $value);
}
}
$form->addElement($el);
}
return $form;
}
// Seems this function will become obsolete if we use the static $creoleTypeMapping
function parseTypeInfoFromColumn ( $column ) {
return array(
'type' => 'String',
'attributes' => array()
);
}
}

View file

@ -0,0 +1,201 @@
<?php
/**
* patForms_Creator_DB examples
*
* patForms_Creator is a subpackage of patForms that provides
* several formbuilder classes that create a form from
* a datasource.
*
* WARNING:
* The Creator subpackage is still in devel state!
*
* @access public
* @package patForms
* @subpackage Examples
* @author Stephan Schmidt <schst@php-tools.net
* @author Sebastian Mordziol <argh@php-tools.net>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
/**
* Main examples prepend file, needed *only* for the examples framework!
*/
//include_once 'patExampleGen/prepend.php';
//$exampleGen->displayHead( 'Example' );
include('include/common.php');
// EXAMPLE START ------------------------------------------------------
/**
* main patForms class
*/
require_once ('patForms.php');
/**
* patErrorManager class
*/
require_once ('patErrorManager.php');
// create the creator :)
$creator = &patForms::createCreator( 'Propel' );
// create the form object from the given propel Object class instance
require_once('model/general/UserProfile.php');
$userProfile = UserProfilePeer::retrieveByPK(1);
$form =& $creator->create( $userProfile );
//$wikipage = WikipagePeer::retrieveByPK('wiki');
//$form =& $creator->create($wikipage);
// create the needed renderer
$renderer =& patForms::createRenderer( "Array" );
// set the renderer
$form->setRenderer( $renderer );
// use auto-validation
$form->setAutoValidate( 'save' );
// serialize the elements
$elements = $form->renderForm();
// ERROR DISPLAY ------------------------------------------------------
if ( $form->isSubmitted() )
{
displayErrors( $form ); // see patExampleGen/customFunctions.php
}
// DISPLAY FORM ------------------------------------------------------
displayForm( $form, $elements ); // see patExampleGen/customFunctions.php
/**
* Takes a patForms object, asks it if there are any validation
* errors and displays them if need be.
*
* NOTE: this is just a helper method for our examples collection,
* so that you may concentrate on the relevant parts of the examples.
* It does in no way represent the way it should be done :)
*
* @access public
* @param object &$form The patForms object to use
*/
function displayErrors( &$form )
{
// get the errors from the form object - if there are none,
// this returns false so it is easy to check if there are any.
$errors = $form->getValidationErrors();
// if there are any errors, display them.
if ( $errors )
{
echo '<div class="piErrors">';
echo ' <div class="piErrorsTitle">Validation failed</div>';
echo ' <div class="piErrorsContent">';
// the errors collection is an associative array with the
// field names as keys, so we go through that.
foreach ( $errors as $elementName => $elementErrors )
{
$element =& $form->getElementByName( $elementName );
// each element can have more than one error - this
// is rare, but can happen so this is an indexed array
// with one error in each row.
foreach ( $elementErrors as $row => $error )
{
echo ' <div class="piError">';
echo ' <b>'.$element->getAttribute( 'label' ).':</b> '.$error['message'].'('.$error['element'].' element error #'.$error['code'].')<br/>';
echo ' </div>';
}
}
echo ' </div>';
echo '</div>';
}
// no errors, tell the world everything is fine
else
{
echo '<div class="piHint">Validation successful.</div>';
}
}
/**
* Displays a standard form from the examples collection when the
* form is rendered via the array renderer. Does not work for any
* other examples.
*
* NOTE: this is just a helper method for our examples collection,
* so that you may concentrate on the relevant parts of the examples.
* It does in no way represent the way it should be done :)
*
* @access public
* @param object &$form The current form object
* @param array $elements The rendered elements from the
* @return
* @see
*/
function displayForm( &$form, $elements )
{
// output the opening form tag
echo $form->serializeStart();
echo "<table>\n";
foreach ( $elements as $element ) {
}
echo "</table>\n";
// display all elements
foreach ( $elements as $element )
{
if (!isset($element['description'])) {
// would choke a warning on hidden fields
// strange enough, we've no $element['type'] for hidden inputs
echo $element['element'] . "\n";
continue;
}
echo '<div style="margin-bottom:8px;">';
echo $element['label']."<br>";
echo "<div>".$element["element"]."</div>";
echo "<i>".$element["description"]."</i><br>";
echo '</div>';
//} else {
//echo "<tr><td>".$element['description']."</td><td>".$element['element']."</td></tr>\n";
//}
}
// submit button, closing form tag
echo '<input type="submit" name="save" value="Save form"/><br><br>';
echo $form->serializeEnd();
// form submitted? display all form values
if ( $form->isSubmitted() ) {
$els =& $form->getElements();
$cnt = count( $els );
echo '<div class="piValues">';
echo ' <div class="piValuesTitle">Submitted form values</div>';
echo ' <div class="piValuesContent">';
echo ' <table cellpadding="2" cellspacing="0" border="0">';
for ( $i = 0; $i < $cnt; $i++ ) {
echo '<tr>';
echo ' <td>'.$els[$i]->getAttribute('label').'</td><td>&nbsp;:&nbsp;</td><td>'.$els[$i]->getValue().'</td>';
echo '</tr>';
}
echo ' </table>';
echo ' </div>';
echo '</div>';
}
}

View file

@ -0,0 +1,70 @@
<?php
class patForms_Datasource_Propel {
private $peername;
private $label;
private $value;
public function __construct($conf) {
$this->peername = $conf['peername'];
$this->label = $conf['label'];
$this->value = $conf['value'];
}
public function getValues() {
$map = call_user_func(array($this->peername, 'getPhpNameMap'));
$c = new Criteria();
$c->clearSelectColumns();
foreach (array($this->label, $this->value) as $arr) {
foreach ($arr['members'] as $member) {
if (is_array($member)) {
foreach ($member as $member) {
$c->addSelectColumn(constant($this->peername . '::' . $map[$member]));
}
} else {
$c->addSelectColumn(constant($this->peername . '::' . $map[$member]));
}
}
}
if (isset($this->label['initial']) OR isset($this->value['initial'])) {
$label = isset($this->label['initial']) ? $this->label['initial'] : '';
$value = isset($this->value['initial']) ? $this->value['initial'] : '';
$result[] = array(
'value' => $value,
'label' => $label
);
}
$rs = AuthorPeer::doSelectStmt($c);
$rs->setFetchmode(ResultSet::FETCHMODE_ASSOC);
while ($rs->next()) {
$row = $rs->getRow();
foreach (array('label', 'value') as $key) {
$arr = $this->$key;
$params = array($arr['mask']);
foreach ($arr['members'] as $member) {
if (is_array($member)) {
foreach ($member as $member) {
$field_name = strtolower($map[$member]); // TODO is this always true?
$params[] = $row[$field_name];
}
} else {
$field_name = strtolower($map[$member]); // TODO is this always true?
$params[] = $row[$field_name];
}
}
$$key = call_user_func_array('sprintf', $params);
$tmp[$key] = $$key;
}
$result[] = $tmp;
}
return $result;
}
}

View file

@ -0,0 +1,122 @@
<?
class patForms_Definition {
private $data = array();
public function __construct($name, $autoValidate = '') {
$this->data['name'] = $name;
$this->data['mtime'] = time();
if ($autoValidate) {
$this->data['autoValidate'] = $autoValidate;
}
}
static public function create($conf) {
// TODO
}
public function __get($name) {
if (isset($this->data[$name])) {
return $this->data[$name];
}
}
// TODO change protocol to addElement(array $element)
public function addElement($name, $type, $attributes = array(), $rules = array()) {
if (is_array($type)) {
extract($type);
}
$this->data['elements'][$name]['name'] = $name;
$this->data['elements'][$name]['type'] = $type;
foreach ($attributes as $key => $value) {
$value = $this->cast($value);
$this->data['elements'][$name]['attributes'][$key] = $value;
}
foreach ($rules as $key => $rule) {
$this->data['elements'][$name]['rules'][$key] = $rule;
}
}
public function load($filename) {
$data = $this->read($filename);
foreach ($data as $key => $value) {
if ($key == 'elements') {
foreach ($value as $name => $element) {
$this->addElement($name, $element);
}
} else {
$this->data[$key] = $this->cast($value);
}
}
}
public function save($filename) {
$this->write($filename, $this->data);
}
protected function read($filename) {
$xml = file_get_contents($filename);
$unserializer = new XML_Unserializer();
$unserializer->unserialize($xml);
return $unserializer->getUnserializedData();
}
protected function write($filename, $data) {
$serializer = new XML_Serializer(array (
'addDecl' => true,
'encoding' => 'ISO-8859-1',
'indent' => ' ',
'rootName' => 'form',
'defaultTagName' => 'tag'
));
$serializer->serialize($data);
$xml = $serializer->getSerializedData();
$fp = fopen($filename, 'w+');
fputs($fp, $xml);
fclose($fp);
}
protected function cast($value) {
return $value;
// seems as if patForms_Element(s) are broken here
// e.g. in patForms_Element_Text::serializeHtmlDefault()
// at line 245 if ( $this->attributes['display'] == 'no' )
// will result to true if the display attribute is set
// to (php boolean) true
// so casting the 'true'/'false' and 'yes'/'no' values
// would break intended behaviour here
if (is_array($value) OR is_bool($value)) {
return $value;
}
if ($value === 'true') {
return true;
}
if ($value === 'false') {
return false;
}
if (preg_match('/^[+-]?[0-9]+$/', $value)) {
settype($value, 'int');
return $value;
}
if (preg_match('/^[+-]?[0-9]*\.[0-9]+$/', $value)) {
settype($value, 'double');
return $value;
}
return $value;
}
}

View file

@ -0,0 +1,165 @@
<?
class patForms_Definition_Propel extends patForms_Definition {
private static $creoleTypeMap = array(
CreoleTypes::BOOLEAN => 'Switch', // BOOLEAN = 1;
CreoleTypes::BIGINT => 'String', // BIGINT = 2;
CreoleTypes::SMALLINT => 'String', // SMALLINT = 3;
CreoleTypes::TINYINT => 'String', // TINYINT = 4;
CreoleTypes::INTEGER => 'String', // INTEGER = 5;
CreoleTypes::CHAR => 'String', // CHAR = 6;
CreoleTypes::VARCHAR => 'String', // VARCHAR = 7;
CreoleTypes::FLOAT => 'String', // FLOAT = 8;
CreoleTypes::DOUBLE => 'String', // DOUBLE = 9;
CreoleTypes::DATE => 'String', // DATE = 10;
CreoleTypes::TIME => 'String', // TIME = 11;
CreoleTypes::TIMESTAMP => 'Date', // TIMESTAMP = 12;
CreoleTypes::VARBINARY => 'String', // VARBINARY = 13;
CreoleTypes::NUMERIC => 'String', // NUMERIC = 14;
CreoleTypes::BLOB => 'Text', // BLOB = 15;
CreoleTypes::CLOB => 'Text', // CLOB = 16;
CreoleTypes::TEXT => 'Text', // TEXT = 17;
CreoleTypes::LONGVARCHAR => 'Text', // LONGVARCHAR = 17;
CreoleTypes::DECIMAL => 'String', // DECIMAL = 18;
CreoleTypes::REAL => 'String', // REAL = 19;
CreoleTypes::BINARY => 'String', // BINARY = 20;
CreoleTypes::LONGVARBINARY => 'Text', // LONGVARBINARY = 21;
CreoleTypes::YEAR => 'String', // YEAR = 22;
CreoleTypes::ARR => 'String',
CreoleTypes::OTHER => 'String'
);
private static $validatorTypeMap = array(
'unique' => null,
'minLength' => 'patForms_Rule_MinLength',
'maxLength' => 'patForms_Rule_MaxLength',
'minValue' => 'patForms_Rule_MinValue',
'maxValue' => 'patForms_Rule_MaxValue',
'match' => 'patForms_Rule_Match',
'notMatch' => 'patForms_Rule_NotMatch',
'required' => null, // will be done by the elements "required" attribute
'validValues' => 'patForms_Rule_ValidValues',
);
/**
* @param array $conf an assoc array of parameters. these are:
* - string name => $name of the propel object class
* - string filename => $filename of the form definition xml file
*/
static public function create($conf) {
extract($conf);
$autoValidate = isset($autoValidate) ? $autoValidate : 'save';
$definition = new patForms_Definition_Propel($name, $autoValidate);
if (0 AND file_exists($filename)) {
// load definition from xml file
$definition->load($filename);
} else {
// populate definition from table map and save it to xml file
$definition = self::populateFromTableMap($definition, $conf);
$definition->save($filename);
}
return $definition;
}
private function populateFromTableMap($definition, $conf) {
extract($conf);
$mapBuilder = call_user_func(array($name . 'Peer', 'getMapBuilder'));
$tablename = constant($name . 'Peer::TABLE_NAME');
$tableMap = $mapBuilder->getDatabaseMap()->getTable($tablename);
$cols = $tableMap->getColumns();
foreach ($cols as $col) {
$phpname = $col->getPhpName();
// this would need a patched version of patForms in order
// to retrieve request vars after having submitted the form
// TODO - ask patForms developers to enable this
// $elementName = $tablename . '[' . $phpname . ']';
$elementName = $phpname;
$elementType = self::$creoleTypeMap[$col->getCreoleType()];
// TODO somehow retrieve element type specific default values?
$elementAttributes = array(
'name' => $elementName,
'title' => $phpname,
'label' => $phpname,
'description' => $phpname,
'edit' => 'yes',
'display' => $col->isPrimaryKey() ? 'no' : 'yes',
// Is the element required?
// TODO Can we retrieve this info from the Column object?
'required' => true,
);
switch ($col->getCreoleType()) {
case CreoleTypes::BOOLEAN: {
$elementAttributes['value'] = 1;
break;
}
case CreoleTypes::DATE: {
// TODO doesn't seem to work for some reason
// $elementAttributes['format'] = 'date';
// $elementAttributes['dateformat'] = 'Ymd';
break;
}
}
if ($col->isForeignKey()) {
$relColname = $col->getRelatedColumnName();
$relTablename = $col->getRelatedTableName();
$relColPhpname =
Propel::getDatabaseMap(constant($relTablename . 'Peer::DATABASE_NAME'))->
getTable($relTablename)->getColumn($relColname)->getPhpname();
$elementAttributes['datasource'] = array (
'name' => 'patForms_Datasource_Propel',
'peername' => $relTablename . 'Peer',
'label' => array(
'initial' => 'Please select one ...',
'members' => array($relColPhpname),
'mask' => '%s',
),
'value' => array(
'members' => array($relColPhpname),
'mask' => '%s',
),
);
$elementType = 'Enum';
}
$rules = array();
if ($col->hasValidators()) {
foreach ($col->getValidators() as $validator) {
$name = $validator->getName();
$type = self::$validatorTypeMap[$name];
if (!is_null($type)) {
$rules[$name] = array (
'table' => $col->getTablename(),
'col' => $col->getColumnName(),
'name' => $name,
'type' => self::$validatorTypeMap[$name],
'value' => $validator->getValue(),
'class' => $validator->getClass(),
'message' => $validator->getMessage(),
);
}
}
}
$definition->addElement($phpname, $elementType, $elementAttributes, $rules);
}
return $definition;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,340 @@
<?php
/**
* patForms rule base class
*
* $Id: Rule.php 1347 2009-12-03 21:06:36Z francois $
*
* @access protected
* @package patForms
* @subpackage Rules
*/
/**
* patForms rule base class
*
* @access protected
* @package patForms
* @subpackage Rules
* @author Stephan Schmidt <schst@php-tools.net>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
* @todo implement javascript helper methods (set a javascript property plus an
* array of keys that will be replaced by the properties of the rule)
*/
class patForms_Rule
{
/**
* time when the rule should be applied
*
* Possible values are:
* -PATFORMS_RULE_BEFORE_VALIDATION
* -PATFORMS_RULE_AFTER_VALIDATION
* -PATFORMS_RULE_BOTH
*
* @access private
* @var integer
*/
var $_time = PATFORMS_RULE_AFTER_VALIDATION;
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array();
/**
* script that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array();
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array();
/**
* store the container of the rule
*
* @access private
* @var object
*/
var $container;
/**
* define error codes an messages for each form element
*
* @abstract
* @access private
* @var array
*/
var $validatorErrorCodes = array();
/**
* error code offset for the rule
*
* @abstract
* @access private
*/
var $errorOffset;
/**
* format of the rule
*
* @abstract
* @access private
*/
var $format = 'html';
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = '';
/**
* Get the time when the rule should be applied.
*
* This has to be defined in the _time property of the rule.
*
* @access public
* @return integer
*/
function getTime()
{
return $this->_time;
}
/**
* create a new rule object
*
* @access public
* @param string id
*/
function patForms_Rule( $id = null )
{
if ( $id === null )
{
$id = uniqid( '' );
}
$this->_id = $id;
}
/**
* set the id for the rule
*
* @access public
* @param string id
*/
function setId( $id )
{
$this->_id = $id;
}
/**
* set the locale, this is needed to update the rule
* translations, that have been passed to the container
* element
*
* @access public
* @param string new locale
* @return boolean
*/
function setLocale( $locale )
{
// rules do not store locale information
if (!patForms::isCustomLocale($locale)) {
return true;
}
$errorMessages = patForms::getCustomLocale($locale, 'Rule::' . $this->getRuleName());
if (is_array($errorMessages)) {
$this->validatorErrorCodes[$locale] = $errorMessages;
}
$this->container->addValidatorErrorCodes( $this->validatorErrorCodes, $this->errorOffset );
return true;
}
/**
* prepare the rule
*
* This method is used to initialize the rule.
* By default it adds it validatorErrorCodes
* to the container and stores a reference to the
* container.
*
* You may extend it in your custom rules, but should always be calling
* this method using:
*
* <code>
* patForms_Rule::prepareRule( $container );
* </code>
*
* @access public
* @param object Either a patForms or patForms_Element object
*/
function prepareRule( &$container )
{
$this->format = $container->getFormat();
$this->container = &$container;
$this->errorOffset = $container->getErrorOffset();
$container->addValidatorErrorCodes( $this->validatorErrorCodes, $this->errorOffset );
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @abstract
* @access public
* @param object Either a patForms or patForms_Element object
* @return boolean true, if rule has been applied succesfully, false otherwise
*/
function applyRule( &$container, $type = PATFORMS_RULE_BEFORE_VALIDATION )
{
// your code
}
/**
* addValidationError
*
* @access private
* @param integer $code
* @param array $vars fill named placeholder with values
* @return boolean $result true on success
*/
function addValidationError( $code, $vars = array() )
{
$code= $this->errorOffset + $code;
return $this->container->addValidationError( $code, $vars );
}
/**
* get the name of the rule
*
* By default just return the classname, this is sufficient.
*
* @access public
* @return string
*/
function getRuleName()
{
if (!empty($this->ruleName)) {
return $this->ruleName;
}
return get_class( $this );
}
/**
* get the global javascript of the rule
*
* @access public
* @return string
* @todo Rules need to know the output format
*/
/*
function getGlobalJavascript()
{
if ( isset( $this->globalScript['html'] ) )
{
return $this->globalScript['html'];
}
return '';
}
*/
/**
* get the instance javascript of the rule
*
* @access public
* @return string
*/
/*
function getInstanceJavascript()
{
if ( !isset( $this->instanceScript[$this->format] ) )
{
return false;
}
// get the script for the current format
$script = $this->instanceScript[$this->format];
// always replace the id
$script = str_replace( '[RULE::ID]', $this->_id, $script );
if ( method_exists( $this->container, 'getId' ) )
{
$script = str_replace( '[CONTAINER::ID]', $this->container->getId(), $script );
}
if ( method_exists( $this->container, 'getName' ) )
{
$script = str_replace( '[CONTAINER::NAME]', $this->container->getName(), $script );
}
foreach ( $this->scriptPlaceholders as $placeholder => $property )
{
if ( isset( $this->$property ) )
$script = str_replace( '['.$placeholder.']', $this->$property, $script );
else
$script = str_replace( '['.$placeholder.']', '', $script );
}
return $script;
}
*/
function registerJavascripts(&$form) {
if ($script = $this->getGlobalJavascript()) {
$form->registerGlobalJavascript($this->getRuleName(), $script);
}
if ($script = $this->getInstanceJavascript()) {
$form->registerInstanceJavascript($script);
}
}
function getGlobalJavascript() {
if (isset($this->globalScript[$this->format])) {
return $this->globalScript[$this->format];
}
}
function getInstanceJavascript(){
if (isset($this->instanceScript[$this->format])) {
$script = $this->instanceScript[$this->format];
$script = str_replace('[RULE::ID]', $this->_id, $script);
if (method_exists($this->container, 'getId')) {
$script = str_replace('[CONTAINER::ID]', $this->container->getId(), $script);
}
if (method_exists($this->container, 'getName')) {
$script = str_replace('[CONTAINER::NAME]', $this->container->getName(), $script);
}
foreach ($this->scriptPlaceholders as $placeholder => $property) {
if (isset($this->$property)) {
$script = str_replace('['.$placeholder.']', $this->$property, $script);
} else {
$script = str_replace('['.$placeholder.']', '', $script);
}
}
return $script;
}
}
}

View file

@ -0,0 +1,163 @@
<?php
/**
* patForms Rule Match
*
* This rule matches the field value against a regEx pattern. It successfully
* validates the passed value if the value *does* match the pattern.
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_Match extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::Match */
function pFRC_Match(field) {
this.field = eval('pfe_' + field);
}
pFRC_Match.prototype.validate = function() {
value = this.field.getValue();
if (!value.match(this.pattern)) {
alert('This is an invalid value.');
}
}
pFRC_Match.prototype.setValue = function(pattern) {
this.pattern = pattern;
}
/* END: patForms::Rule::Match */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_Match('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'Match';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "This is an invalid value.",
),
"de" => array(
1 => "Dies ist ein ungültiger Wert.",
),
"fr" => array(
1 => "This is an invalid value.",
)
);
/**
* the regEx pattern
* @access private
* @var string
*/
var $_pattern;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
private $value = 10;
public function __construct($params) {
parent::__construct();
extract($params);
$this->_pattern = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (preg_match($this->_pattern, $element->getValue()) != 0){
return true;
}
$this->addValidationError(1);
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setValue(%s);\n", $this->_id, $this->_pattern);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,161 @@
<?php
/**
* patForms Rule MaxLength
*
* This is just a simple rule, that checks for a required minimum length of a field
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_MaxLength extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::MaxLength */
function pFRC_MaxLength(field) {
this.field = eval('pfe_' + field);
}
pFRC_MaxLength.prototype.validate = function() {
value = this.field.getValue();
if (value.length > this.value) {
alert('Please enter a value that is max. ' + this.value + ' characters long.');
}
}
pFRC_MaxLength.prototype.setValue = function(value) {
this.value = value;
}
/* END: patForms::Rule::MaxLength */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_MaxLength('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'MaxLength';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "Please enter a value that is max. [VALUE] characters long.",
),
"de" => array(
1 => "Bitte geben Sie einen max. [VALUE] Zeichen langen Wert ein.",
),
"fr" => array(
1 => "Please enter a value that is max. [VALUE] characters long.",
)
);
/**
* possible values
* @access private
* @var array
*/
var $_values;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
private $value = 10;
public function __construct($params) {
parent::__construct();
extract($params);
$this->value = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (strlen($element->getValue()) <= $this->value) {
return true;
}
$this->addValidationError(1, array('value' => $this->value));
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setValue(%s);\n", $this->_id, $this->value);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,163 @@
<?php
/**
* patForms Rule MaxValue
*
* This rule simply checks for a required maximum value (number) of a field
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_MaxValue extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::MaxValue */
function pFRC_MaxValue(field) {
this.field = eval('pfe_' + field);
}
pFRC_MaxValue.prototype.validate = function() {
value = this.field.getValue();
if (parseInt(value) != value) {
alert('Please enter a number that is less or equal to ' + this.value);
}
if (parseInt(value) > this.value) {
alert('Please enter a number that is less or equal to ' + this.value);
}
}
pFRC_MaxValue.prototype.setMaxValue = function(value) {
this.value = value;
}
/* END: patForms::Rule::MaxValue */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_MaxValue('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'MaxValue';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "Please enter a number that is less or equal to [VALUE].",
),
"de" => array(
1 => "Bitte geben Sie eine Zahl kleiner oder gleich [VALUE] ein.",
),
"fr" => array(
1 => "Please enter a number that is less or equal to [VALUE].",
)
);
/**
* the regEx pattern
* @access private
* @var string
*/
var $_value;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
public function __construct($params) {
parent::__construct();
extract($params);
$this->_value = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (intval($element->getValue()) <= intval($this->_value)){
return true;
}
$this->addValidationError(1, array('value' => $this->_value));
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setMaxValue(%s);\n", $this->_id, $this->_value);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,161 @@
<?php
/**
* patForms Rule MinLength
*
* This is just a simple rule, that checks for a required minimum length of a field
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_MinLength extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::MinLength */
function pFRC_MinLength(field) {
this.field = eval('pfe_' + field);
}
pFRC_MinLength.prototype.validate = function() {
value = this.field.getValue();
if (value.length < this.value) {
alert('Please enter a value that is at least ' + this.value + ' characters long.');
}
}
pFRC_MinLength.prototype.setValue = function(value) {
this.value = value;
}
/* END: patForms::Rule::MinLength */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_MinLength('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'MinLength';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "Please enter a value that is at least [VALUE] characters long.",
),
"de" => array(
1 => "Bitte geben Sie einen mindestens [VALUE] Zeichen langen Wert ein.",
),
"fr" => array(
1 => "Please enter a value that is at least [VALUE] characters long.",
)
);
/**
* possible values
* @access private
* @var array
*/
var $_values;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
private $value = 10;
public function __construct($params) {
parent::__construct();
extract($params);
$this->value = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (strlen($element->getValue()) >= $this->value) {
return true;
}
$this->addValidationError(1, array('value' => $this->value));
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setValue(%s);\n", $this->_id, $this->value);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,165 @@
<?php
/**
* patForms Rule MinValue
*
* This rule simply checks for a required minimum value (number) of a field
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_MinValue extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::MinValue */
function pFRC_MinValue(field) {
this.field = eval('pfe_' + field);
}
pFRC_MinValue.prototype.validate = function() {
value = this.field.getValue();
if (parseInt(value) != value) {
alert('Please enter a number that is greater or equal to ' + this.value);
}
if (parseInt(value) < this.value) {
alert('Please enter a number that is greater or equal to ' + this.value);
}
}
pFRC_MinValue.prototype.setMinValue = function(value) {
this.value = value;
}
/* END: patForms::Rule::MinValue */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_MinValue('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'MinValue';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "Please enter a number that is greater or equal to [VALUE].",
),
"de" => array(
1 => "Bitte geben Sie eine Zahl größer oder gleich [VALUE] ein.",
),
"fr" => array(
1 => "Please enter a number that is greater or equal to [VALUE].",
)
);
/**
* the regEx pattern
* @access private
* @var string
*/
var $_value;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
private $value = 10;
public function __construct($params) {
parent::__construct();
extract($params);
$this->_value = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (intval($element->getValue()) >= intval($this->_value)){
return true;
}
$this->addValidationError(1, array('value' => $this->_value));
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setMinValue(%s);\n", $this->_id, $this->_value);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,163 @@
<?php
/**
* patForms Rule NotMatch
*
* This rule matches the field value against a regEx pattern. It successfully
* validates the passed value if the value does *not* match the pattern.
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_NotMatch extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::NotMatch */
function pFRC_NotMatch(field) {
this.field = eval('pfe_' + field);
}
pFRC_NotMatch.prototype.validate = function() {
value = this.field.getValue();
if (value.match(this.pattern)) {
alert('This is an invalid value.');
}
}
pFRC_NotMatch.prototype.setValue = function(pattern) {
this.pattern = pattern;
}
/* END: patForms::Rule::NotMatch */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_NotMatch('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'NotMatch';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "This is an invalid value.",
),
"de" => array(
1 => "Dies ist ein ungültiger Wert.",
),
"fr" => array(
1 => "This is an invalid value.",
)
);
/**
* the regEx pattern
* @access private
* @var string
*/
var $_pattern;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
private $value = 10;
public function __construct($params) {
parent::__construct();
extract($params);
$this->_pattern = $value;
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (preg_match($this->_pattern, $element->getValue()) == 0){
return true;
}
$this->addValidationError(1);
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
$script = sprintf("pfr_%s.setValue(%s);\n", $this->_id, $this->_pattern);
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,182 @@
<?php
/**
* patForms Rule ValidValues
*
* This is just a simple rule, that checks for a required minimum length of a field
*
* @package patForms
* @subpackage Rules
* @author Sven Fuchs <svenfuchs@artweb-design.de>
* @license LGPL, see license.txt for details
* @link http://www.php-tools.net
*/
class patForms_Rule_ValidValues extends patForms_Rule
{
/**
* script that will be displayed only once
*
* @access private
* @var array
*/
var $globalScript = array(
'html' => "/* patForms::Rule::ValidValues */
Array.prototype.inArray = function(value) {
var i;
for (i=0; i < this.length; i++) {
if (this[i] === value) {
return true;
}
}
return false;
};
function pFRC_ValidValue(field) {
this.field = eval('pfe_' + field);
}
pFRC_ValidValue.prototype.validate = function() {
value = this.field.getValue();
for (var i = 0; i < this.values.length; i++) {
if (this.values[i] === value) {
return true;
}
}
var msg = 'Please enter one of the following values: ';
for (var i = 0; i < this.values.length; i++) {
msg = msg + this.values[i];
if (i < this.values.length - 1) {
msg = msg + ', ';
}
}
alert(msg);
}
pFRC_ValidValue.prototype.setValues = function(values) {
this.values = values;
}
/* END: patForms::Rule::ValidValue */
"
);
/**
* javascript that will be displayed once per instance
*
* @access private
* @var array
*/
var $instanceScript = array(
'html' => "var pfr_[RULE::ID] = new pFRC_ValidValue('[CONTAINER::NAME]');\n"
);
/**
* properties that have to be replaced in the instance script.
*
* @access private
* @var array
*/
var $scriptPlaceholders = array(
'RULE::SOURCE' => '_source',
);
/**
* name of the rule
*
* @abstract
* @access private
*/
var $ruleName = 'ValidValue';
/**
* define error codes and messages for the rule
*
* @access private
* @var array $validatorErrorCodes
* @todo translate error messages
*/
var $validatorErrorCodes = array(
"C" => array(
1 => "Please enter one of the following values: [VALUES].",
),
"de" => array(
1 => "Bitte geben Sie einen der folgenden Werte ein: [VALUES].",
),
"fr" => array(
1 => "Please enter one of the following values: [VALUES].",
)
);
/**
* possible values
* @access private
* @var array
*/
var $_values;
/**
* field id that is used
* @access private
* @var string
*/
var $_field;
public function __construct($params) {
parent::__construct();
extract($params);
$this->_values = explode('|', $value);
}
/**
* prepare the rule
*
* @access public
* @param object patForms
*/
function prepareRule(&$container) {
patForms_Rule::prepareRule($container);
$onChange = $container->getAttribute('onchange');
$newHandler = sprintf('pfr_%s.validate();', $this->_id);
$container->setAttribute('onchange', $newHandler . $onChange);
return true;
}
/**
* method called by patForms or any patForms_Element to validate the
* element or the form.
*
* @access public
* @param object patForms form object
*/
function applyRule(&$element, $type = PATFORMS_RULE_AFTER_VALIDATION) {
if (in_array($element->getValue(), $this->_values)) {
return true;
}
$this->addValidationError(1, array('values' => implode(', ', $this->_values)));
return false;
}
/**
*
*
* @access public
*/
function registerJavascripts(&$form) {
parent::registerJavascripts($form);
foreach ($this->_values as $value) {
$values[] = "'$value'";
}
$script = sprintf("pfr_%s.setValues(new Array(%s));\n", $this->_id, implode(', ', $values));
$form->registerInstanceJavascript($script);
}
}

View file

@ -0,0 +1,146 @@
<?php
class patForms_Storage_Propel extends patForms_Storage
{
private $peer;
private $peername;
public function setStorageLocation($peername) {
$this->peer = new $peername();
$this->peername = $peername;
$parts = explode('.', explode('.', $this->peer->getOMClass()));
$this->classname = array_pop($parts);
$this->setPrimaryField('Id');
}
private function getCriteria($values) {
$object = new $this->classname();
//$object->populateFromArray($values); //TODO use a workaround until we'll get phpNamed keys in populateFromArray()
$object = $this->populateObjectFromArray($object, $values);
return $object->buildPkeyCriteria();
}
/**
* get an entry
*
* This tries to find an entry in the storage container
* that matches the current data that has been set in the
* form and populates the form with the data of this
* entry
*
* @access public
* @param object patForms patForms object that should be stored
* @return boolean true on success
*/
public function loadEntry(&$form) {
if (!$object = $this->_entryExists($form->getValues())) {
// entry does not exists (why return an array here??)
return array();
}
$form->setValues($object->toArray());
return true;
}
public function validateEntry(&$form) {
if (!$object = $this->_entryExists($form->getValues())) {
$object = new $this->classname();
}
//$object->populateFromArray($form->getValues()); //TODO use a workaround until we'll get phpNamed keys in populateFromArray()
$object = $this->populateObjectFromArray($object, $form->getValues());
$result = $object->validate();
if ($result !== true) {
$mapBuilder = $this->peer->getMapBuilder();
$dbMap = $mapBuilder->getDatabaseMap();
foreach ($result as $colname => $error) {
list($tablename, $colname) = explode('.', $colname);
$column = $dbMap->getTable($tablename)->getColumn($colname);
$element = $form->getElement($column->getPhpName());
$element->addValidatorErrorCodes(array(
'C' => array(
1 => $error->getMessage() . ' (occured in Storage)',
),
), 1000);
$element->addValidationError(1001);
}
return false;
}
}
/**
* adds an entry to the storage
*
* @param object patForms patForms object that should be stored
* @return boolean true on success
*/
public function _addEntry(&$form) {
$object = new $this->classname();
//$object->populateFromArray($form->getValues()); //TODO use a workaround until we'll get phpNamed keys in populateFromArray()
$object = $this->populateObjectFromArray($object, $form->getValues());
$object->save();
return true;
}
/**
* updates an entry in the storage
*
* @param object patForms patForms object that should be stored
* @return boolean true on success
*/
public function _updateEntry(&$form, $primary) {
$object = $this->_entryExists($form->getValues());
//$object->populateFromArray($form->getValues()); //TODO use a workaround until we'll get phpNamed keys in populateFromArray()
$object = $this->populateObjectFromArray($object, $form->getValues());
$object->save();
return true;
}
/**
* check, whether an entry exists
*
* @access private
* @param array
*/
public function _entryExists($values) {
// This method gets called multiple times, e.g. when an existing
// object gets updated. We'll therefor cache results locally using
// a criteria string representation as hash.
static $objects;
$criteria = $this->getCriteria($values);
$hash = $criteria->toString();
if (isset($objects[$hash])) {
return $objects[$hash];
}
$objects[$hash] = $this->peer->doSelectOne($criteria);
if (empty($objects[$hash])) {
return false;
}
return $objects[$hash];
}
// this method is just a workaround
private function populateObjectFromArray($object, $values) {
foreach (array_keys($object->toArray()) as $key) {
if (array_key_exists($key, $values)) {
$object->{'set' . $key}($values[$key]);
}
}
return $object;
}
}

View file

@ -0,0 +1,94 @@
<patTemplate:tmpl name="page">
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>{TITLE}</title>
<style>
body {
font: normal 13px arial;
}
form div.row {
clear: left;
float: left;
margin-bottom: 5px;
}
form label {
float: left !important;
display: block;
width: 100px;
}
form div div {
float: left !important;
margin: 0px 10px 0px 0px;
}
form div.descr {
font-style: italic;
}
form div.buttons {
clear: left;
padding: 5px 0px 0px 100px;
}
form div.errors {
border: solid 1px #666666;
margin-bottom: 25px;
padding-bottom: 10px;
background: #f6f6f6;
}
form div.errors h3 {
background: #666666;
color: #ffffff;
font-size: 14px;
padding: 2px 5px 2px 10px;
margin: 0px;
}
form div.errors p {
padding: 10px 10px 10px 10px;
margin: 0px;
}
form div.errors ul {
margin: 0px;
padding-left: 24px;
}
input, select {
font: normal 12px arial;
}
</style>
</head>
<body>
<patTemplate:tmpl name="form">
{START}
<pattemplate:tmpl name="errors" visibility="hidden">
<div class="errors">
<h3>Validation failed</h3>
<p>Sorry, your input could not be saved for the following reasons:</p>
<ul>
<pattemplate:tmpl name="error">
<li><b>{FIELD}:</b> {MESSAGE}</li>
</pattemplate:tmpl>
</ul>
</div>
</pattemplate:tmpl>
<patTemplate:tmpl name="elements" type="condition" conditionvar="display">
<patTemplate:sub condition="no">
{ELEMENT}
</patTemplate:sub>
<patTemplate:sub condition="__default">
<div class="row">
<label for="{ID}" title="{TITLE}">{LABEL}:</label>
<div>{ELEMENT}</div>
<div class="descr">{DESCRIPTION}</div>
</div>
</patTemplate:sub>
</patTemplate:tmpl>
<div class="buttons">
<input type="submit" name="save" value="Save form"/>
</div>
{END}
</patTemplate:tmpl>
</body>
</html>
</patTemplate:tmpl>

View file

@ -0,0 +1,10 @@
# This first example is tested with a Bookstore project on MySql
# (default setting Sqlite has not been tested)
#
# Additionally, you'll need some data in your tables. In case you
# don't have - here's a mini-dump to get the example running.
INSERT INTO `author` VALUES (1, 'Martin', 'Heidegger');
INSERT INTO `book` VALUES (1, 'Sein und Zeit', '3484701226', NULL, NULL);
INSERT INTO `publisher` VALUES (1, 'Max Niemeyer Verlag');

View file

@ -0,0 +1,97 @@
<?
function __autoload($classname) {
$filename = str_replace ('_', '/', $classname) . '.php';
require_once $filename;
}
/**
* Required packages:
*
* - Propel Bookstore project (tested only with mysql, not sqlite)
* - patForms (http://www.php-tools.net/site.php?file=patForms)
* - patTemplate (http://www.php-tools.net/site.php?file=patTemplate)
* - Xml_Serializer (http://pear.php.net/package/XML_Serializer)
*
* Installation:
*
* In theorie, it should work to
*
* - download the files from svn/propel/contrib/pat
* - save them anywhere in your servers docroot
* - tweak the following settings and
* - run this file
*/
// change these according to your setup
$pathToBookstore = 'f:/test/propel'; // omit bookstore/ here
$pathToPear = 'f:/pear';
$pathToPat = 'f:/pear/pat';
$path = PATH_SEPARATOR . $pathToBookstore . PATH_SEPARATOR . $pathToPat;
set_include_path(get_include_path() . $path);
// change these according to your propel settings
$classname = 'book';
$path = './patForms/res';
$propelConfFilename = 'conf/bookstore-conf.php';
// uncomment this to edit an existing record
$pk = array('Id' => 2);
/**
* the rest should work out of the box if you don't have any unusal
* types in your database schema.xml (strings, int etc. should work)
*/
require_once 'bookstore/' . $classname . '.php';
Propel::init($propelConfFilename);
// create a form definition
$definition = patForms_Definition_Propel::create(array(
'name' => $classname,
'filename' => $path . '/form.' . $classname . '.xml',
));
// create a storage
$storage = patForms::createStorage('Propel');
$storage->setStorageLocation($classname . 'peer');
// create a form
$form = &patForms::createCreator('Definition')->create($definition);
$form->setRenderer(patForms::createRenderer('Array'));
$form->setStorage($storage);
if (isset($pk)) {
$form->setValues($pk);
}
// render it to a patTemplate (could be done by other template engines)
$tpl = new patTemplate();
$tpl->setRoot($path);
$tpl->readTemplatesFromInput('form.dynamic.tpl');
$tpl->addVar('page', 'title', 'Bookstore party');
$tpl->addVar('form', 'start', $form->serializeStart());
$tpl->addVar('form', 'end', $form->serializeEnd());
$tpl->addRows('elements', $form->renderForm());
// this should be possible to be done in a more elegant way
if ($errors = $form->getValidationErrors()) {
foreach ($errors as $field => $error) {
$tpl->addVar('error', 'field', $field);
foreach ($error as $line) {
$tpl->addVar('error', 'message', $line['message']);
$tpl->addVar('error', 'code', $line['code']);
$tpl->parseTemplate('error', 'a');
}
}
$tpl->setAttribute('errors', 'visibility', 'visible');
}
$tpl->displayParsedTemplate();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,909 @@
<?php
/*
* $Id: Propel.php 1347 2009-12-03 21:06:36Z francois $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://propel.phpdb.org>.
*/
require_once 'HTML/QuickForm.php';
define('HTML_QUICKFORM_PROPEL_NO_COLUMNS', 2);
define('HTML_QUICKFORM_PROPEL_ALL_COLUMNS', 3);
define('HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE', 4);
define('HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN', 5);
/* On large foreign table resultsets propel choked */
# ini_set('memory_limit', '50M');
/**
*
* NOTE: HTML_QuickForm_Propel extends HTML_QuickForm, so all QuickForm functionality is available.
*
* A fictive example:
*
* $className = 'book';
* $id = '7'; // existing item
* $id = null; // when no id is passed, it's assumed we are creating a new item
*
* $quickForm = new HTML_QuickForm_Propel($className, $id); // optionally pass it to the constructor
* $quickForm->setAction('/Bookstore/Form');
* $quickForm->addElement('header', '', 'HTML_QuickForm_Propel');
* $quickForm->setId($id);
* $quickForm->setClassName($className);
* $quickForm->setTarget('_self');
* $quickForm->setMethod('post');
*
* // use this to override the default behaviour for
* // foreign table select boxes, UserPeer::UNAME will be shown in the select list.
* // It defaults to the first string column in the foreign table.
*
* $quickForm->joinColumn(bookPeer::PUBLISHER_ID,UserPeer::UNAME);
*
* // default to all columns shown
* $quickForm->setColumnMode(HTML_QUICKFORM_PROPEL_ALL_COLUMNS);
* $quickForm->hideColumn('PASS');
*
* // or default to no columns shown
* $quickForm->setColumnMode(HTML_QUICKFORM_PROPEL_NO_COLUMNS);
* $quickForm->showColumn('NAME'); // column name without table prefix.
* $quickForm->showColumn('UNAME');
* $quickForm->showColumn('USER_INFO');
* $quickForm->showColumn('EMAIL');
* $quickForm->showColumn('FEMAIL');
* $quickForm->showColumn('URL');
* $quickForm->showColumn('PASS');
*
* // generate the form
* $quickForm->build();
*
* // after the form is build, it's possible to modify the generated elements
* $quickForm->getElement('NAME')->setSize(10); // manually tune this element
*
* if ($quickForm->validate()) {
* $quickForm->freeze();
*
* // save the object we have editted
* $quickForm->save();
* } else {
* $quickForm->toHtml(); // or any other QuickForm render option
* }
*
* TODO: map all creoleTypes to usefull formelements
*
* @author Rob Halff <info@rhalff.com>
* some improvements by Zoltan Nagy (sunshine@freemail.hu)
* @version $Rev: 1347 $
* @copyright Copyright (c) 2005 Rob Halff: LGPL - See LICENCE
* @package propel.contrib
*/
class HTML_QuickForm_Propel extends HTML_QuickForm {
/**
* ID of the Propel Object.
* @var integer
* @access private
*/
private $id;
/**
* Contains column visibility information.
* @var array
* @access private
*/
private $columnVisibility = array();
/**
* Contains titles of columns.
* @var array
* @access private
*/
private $columnTitle = array();
/**
* The Column visibility mode either.
* Possible values:
*
* HTML_QUICKFORM_PROPEL_ALL_COLUMNS
* HTML_QUICKFORM_PROPEL_NO_COLUMNS
*
* @var integer
* @access private
*/
private $columnMode;
/**
* String containing the peerName.
* @var string
* @access private
*/
private $peerName;
/**
* String containing the className of the propel Object.
* @var string
* @access private
*/
private $className;
/**
* The Column objects.
*
* @var array
* @access private
*/
private $cols;
/**
* The Object being operated on.
* @var object
* @access private
*/
private $obj;
/**
* Seperator value.
*
* In case the option list will be build by multiple values
* This is the value these fields will be seperated with
*
* @var string
* @access private
*/
private $seperator = ' ';
/**
*
* Not used yet.
*
* @var array
* @access private
*/
private $joinMap = array();
/**
* The default QuickForm rule type to use.
* Either server or client
*
* @var string
* @access private
*/
private $defaultRuleType = 'server';
/**
* This is used in the QuickForm DateElement
* @var string
* @access private
*/
private $lang = 'en';
/**
* Rulemapping should cover all available propel rules
*
* @var array
* @access private
*/
private $ruleMapping = array(
'mask'=>'regex',
'maxLength'=>'maxlength',
'minLength'=>'minlength',
'maxValue'=>'maxvalue',
'minValue'=>'minvalue',
'required'=>'required',
'validValues'=>'validvalues',
'unique'=>'unique'
);
/**
*
* CreoleType to QuickForm element mapping
*
* @var array
* @access private
*/
private $typeMapping = array(
CreoleTypes::BOOLEAN =>'radio',
CreoleTypes::BIGINT =>'text',
CreoleTypes::SMALLINT =>'text',
CreoleTypes::TINYINT =>'text',
CreoleTypes::INTEGER =>'text',
CreoleTypes::NUMERIC =>'text',
CreoleTypes::DECIMAL =>'text',
CreoleTypes::REAL =>'text',
CreoleTypes::FLOAT =>'text',
CreoleTypes::DOUBLE =>'text',
CreoleTypes::CHAR =>'text',
CreoleTypes::VARCHAR =>'text',
CreoleTypes::LONGVARCHAR=>'textarea',
CreoleTypes::TEXT =>'textarea',
CreoleTypes::TIME =>'text',
CreoleTypes::TIMESTAMP =>'date',
CreoleTypes::DATE =>'date',
CreoleTypes::YEAR =>'text',
CreoleTypes::VARBINARY =>'text',
CreoleTypes::BLOB =>'text',
CreoleTypes::CLOB =>'text',
CreoleTypes::BINARY =>'text',
CreoleTypes::LONGVARBINARY=>'text',
CreoleTypes::ARR =>'text',
CreoleTypes::OTHER =>'text'
);
/**
*
* The Constructor
*
* Classname and id are specific to HTML_QuickForm_Propel
*
* The other parameters are needed to construct the parent QuickForm Class.
*
* @param string className
* @param string id
* @param string formName
* @param string method
* @param string action
* @param string target
* @param array attributes
* @param boolean trackSubmit
*
*/
public function __construct($className = null, $id = null, $formName='HTML_QuickForm_Propel', $method='post', $action='', $target='_self', $attributes=null, $trackSubmit = false)
{
$this->setClassName($className);
$this->setPeerName($className.'Peer'); // Is this always true ?
$this->setId($id);
parent::HTML_QuickForm($formName, $method, $action, $target, $attributes, $trackSubmit);
// set the default column policy
$this->setColumnMode(HTML_QUICKFORM_PROPEL_ALL_COLUMNS);
}
/**
*
* NOT IMPLEMENTED
*
* Allows for creating complex forms.
* Note that limit 1 will always be added to the criteria.
* Because we can only edit one record/row at a time.
*
* However we will be able to join tables in complex ways.
*
* @param Criteria
*
*/
public function setCriteria(Criteria $c)
{
$c->setLimit(1);
$this->criteria = $c;
}
/**
*
* Set the action of this form
*
* @param string action
*
*/
public function setAction($action)
{
$attributes = array('action'=>$action);
$this->updateAttributes($attributes);
}
/**
*
* Set method of this form, e.g. post or get
*
* @param string method
*
*/
public function setMethod($method)
{
$attributes = array('method'=>$method);
$this->updateAttributes($attributes);
}
/**
*
* Set the target of this form
*
* @param string target
*
*/
public function setTarget($target)
{
$attributes = array('target'=>$target);
$this->updateAttributes($attributes);
}
/**
*
* Set the id of the object we need to get
*
* @param string id
*
*/
public function setId($id)
{
$this->id = $id;
}
/**
*
* Set the class
*
* @param string className
*
*/
public function setClassName($className)
{
$this->className = $className;
}
/**
*
* Get the class name
*
* @return string className
*
*/
public function getClassName()
{
return $this->className;
}
private function setPeerName($peerName)
{
$this->peerName = $peerName;
}
/**
*
* Get the peer name
*
* @return string peerName
*
*/
public function getPeerName()
{
return $this->peerName;
}
/**
* Build the form
*
* @return void
*
*/
public function build()
{
if (!class_exists($this->peerName)) {
// some autoloading, dunno if it should belong here.
// or in the users autoload function
//$dbMap = call_user_func(array($this->peerName, 'getMapBuilder'));
// TODO: implement this.
}
if (empty($this->id)) {
// create empty instance of this class
$this->obj = new $this->className();
} else {
// find the object.
if (!$this->obj = call_user_func(array($this->peerName, 'retrieveByPK'), $this->id)) {
// for help me god.. what to do ?
throw new PropelException("HTML_QuickForm_Propel::build(): $this->peerName::retrieveByPK($this->id) failed.");
}
}
// note: getTableMap is protected by default.
// so do this handstand to get the tableMap
$mapBuilder = call_user_func(array($this->peerName, 'getMapBuilder'));
// Note: $dbMap is re-used below to determine foreign table
$dbMap = $mapBuilder->getDatabaseMap();
// Get the column names for this table.
$this->cols = $dbMap->getTable(constant("$this->peerName::TABLE_NAME"))->getColumns();
// Do it the HTML_QuickForm way and use defaultValues
// instead of setValue() on every element.
// we have to first loop through the columns
foreach ($this->cols as $colName=>$col) {
$elementType = $this->typeMapping[$col->getCreoleType()];
if ($elementType == 'date') {
// null returns timestamp
$value = $this->obj->{'get'.$col->getPhpName()}(null);
} else {
$value = $this->obj->{'get'.$col->getPhpName()}();
}
$defaultValues[$colName] = $value;
}
$this->setDefaults($defaultValues);
foreach ($this->cols as $colName=>$col) {
if ($this->isColumnHidden($colName)) {
continue;
}
if ($col->isPrimaryKey()) {
// create a hidden field with primary key
if (!$this->checkColumn($colName, HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE)) {
$this->addElement('hidden', $col->getColumnName(), $col->getColumnName());
continue;
}
}
// element's title
$colTitle = $this->getColumnTitle($colName);
if ($col->isForeignKey()) {
// TODO: check if user created an optional method for populating the select form
// this populating of the select box is just some way to show joined items in a form.
// it could also be checkboxes, radio buttons or whatever kind of widget.
$relatedTable = $dbMap->getTable($col->getRelatedTableName());
$relatedCols = $relatedTable->getColumns();
$relatedPeer = $relatedTable->getPhpName().'Peer';
if (is_callable($relatedPeer, 'doSelect')) {
// TODO: allow set this criteria.
$c = new Criteria;
$relatedList = call_user_func(array($relatedPeer,'doSelect'), $c);
$colConstant = constant($this->peerName.'::'.$colName);
//$relatedColConstant = constant($relatedPeer.'::'.$relatedCol->getColumnName());
$relatedGetter = 'getPrimaryKey';
// TODO: this needs to be array based, to support multiple foreign columns
if (isset($this->joinMap[$colConstant])) {
// translate to getter
$relatedColConstant = $this->joinMap[$colConstant];
if (!$relatedTable->containsColumn($relatedColConstant)) {
// throw exception, there is no such column
throw new PropelException('HTML_QuickForm_Propel::build(): there is no column named '.$relatedTable->normalizeColName($relatedConstant).'in '.$relatedTable->getTableName().' while trying to build the select list');
}
$nameColumn = $relatedTable->getColumn($relatedColConstant);
$relatedGetter = 'get'.$nameColumn->getPhpName();
} else {
//auto detection
// determine the first string column
foreach ($relatedCols as $relatedCol) {
if ($relatedCol->getType() == 'string') {
$relatedGetter = 'get'.$relatedCol->getPhpName();
break;
}
}
}
$selectList = array();
// TODO: not hardcoded here.
$selectList[null] = _('Please selection an option');
foreach ($relatedList as $relObj) {
$key = $relObj->getPrimaryKey();
if (false OR $yesWannaUseEntireObjectsToUseItInTemplate) {
// TODO: IMPLEMENT THIS.
$selectList[$key] = $relObj;
} elseif (false OR $forceSomeKindOfColumnToBeDisplayed) {
// TODO: IMPLEMENT THIS.
} else {
$selectList[$key] = $relObj->{$relatedGetter}();
}
}
if (count($selectList) > 1) { // value of 1 depends on select message being set.
$select =& $this->addElement('select', $colName, $colTitle, $selectList);
} else {
// what to do if no records exists in the foreign table ?
$this->addElement('static', $colName, $colTitle, _('No Records'));
}
}
// do some recursion ?
} else {
//TODO: the mapping is not so generic anymore (to many exceptions)
$elementType = $this->typeMapping[$col->getCreoleType()];
if ($col->getCreoleType() == CreoleTypes::BOOLEAN) {
// TODO: describe how to override these options.
$radio = array();
$radio[] = HTML_QuickForm::createElement('radio', null, null, 'Yes', true);
$radio[] = HTML_QuickForm::createElement('radio', null, null, 'No', false);
$el = $this->addGroup($radio, $colName, $colName);
} else {
$el = $this->addElement(
$elementType,
$colName,
$colTitle);
if ($elementType == 'text') {
$el->setMaxLength($col->getSize());
}
if ($col->getCreoleType() == CreoleTypes::TIMESTAMP) {
/* Option Info:
var $_options = array(
'language' => 'en',
'format' => 'dMY',
'minYear' => 2001,
'maxYear' => 2010,
'addEmptyOption' => false,
'emptyOptionValue' => '',
'emptyOptionText' => '&nbsp;',
'optionIncrement' => array('i' => 1, 's' => 1)
);
*/
// hmm, don't like it but there seems to be no public method
// to set an option afterwards
$el->_options['language'] = $this->lang;
// TODO: is the format always the same in propel ?
$el->_options['format'] = 'Y-F-d H:i:s';
}
}
// add an html id to the element
$this->addElementId($el, $colName);
//$el->setValue($value);
// required rule for NOT NULL columns
if ($col->isNotNull()) {
// TODO: What error message should we use?
$this->addRule($colName,
$this->getColumnTitle($colName) . ' is required',
'required');
}
if ($col->hasValidators()) {
foreach ($col->getValidators() as $validatorMap) {
$this->addRule($colName,
$validatorMap->getMessage(),
$this->ruleMapping[$validatorMap->getName()],
$validatorMap->getValue(),
$this->defaultRuleType
);
}
}
}
}
// should HTML_QuickForm_Propel add this ?
$this->addElement('submit', 'submit', 'Submit');
// do this for the developer, can't think of any case where this is unwanted.
$this->applyFilter('__ALL__', 'trim');
}
/**
*
* Use it to change the locale used for the Date element
*
* @param string locale
* @return void
*
*/
public function setLang($lang)
{
$this->lang = $lang;
}
/**
*
* Save the form.
*
* @return void
*
*/
public function save()
{
$this->copyToObj();
$this->obj->save();
}
/**
*
* Copy form values to Obj.
*
* @return void
*
*/
public function copyToObj()
{
// TODO: check what process does, if we leave out anything important.
if (!isset($this->cols)) {
// throw some error, form cannot be saved before it is build.
throw new PropelException('HTML_QuickForm_Propel::save(): form cannot be saved before it is build.');
}
foreach ($this->cols as $colName=>$col) {
// Has the form got this element?
if ($this->isColumnHidden($colName))
{
continue;
}
$value = $this->getElementValue($colName);
if ($value instanceof HTML_QuickForm_Error)
{
// TODO: What should we do if an error has occured?
continue;
}
$elementType = $this->typeMapping[$col->getCreoleType()];
// quickform doesn't seem to give back a timestamp, so calculate the date manually.
if ($elementType == 'date') {
$date = array(
'D' => null,
'l' => null,
'd' => null,
'M' => null,
'm' => null,
'F' => null,
'Y' => null,
'y' => null,
'h' => null,
'H' => null,
'i' => null,
's' => null,
'a' => null,
'A' => null
);
foreach ($value as $key=>$val) {
$date[$key] = $val[0];
}
$value = mktime($date['h'], $date['m'], $date['s'], $date['M'], $date['d'], $date['Y']);
}
$this->obj->{'set'.$col->getPhpName()}($value);
}
}
/**
*
* Get the object we are operating on.
*
* @return object a propel object
*
*/
public function getObj()
{
return $this->obj;
}
/**
* What to do if a delete button is added
* and the user clicks on it, after the object has been delete in save()
*/
public function onDelete()
{
}
public function createDeleteButton()
{
return $this->addElement('submit', 'delete', 'Delete');
}
public function isColumnHidden($column)
{
if ($this->checkColumn($column, HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN) && $this->columnMode == HTML_QUICKFORM_PROPEL_ALL_COLUMNS) {
return true;
}
if (!$this->checkColumn($column, HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE) && $this->columnMode == HTML_QUICKFORM_PROPEL_NO_COLUMNS) {
return true;
}
return false;
}
private function checkColumn($column, $state)
{
if (isset($this->columnVisibility[$column])) {
return ($this->columnVisibility[$column] == $state);
} else {
return false;
}
}
/**
*
* Sets the default visibility mode
*
* This must be either:
* HTML_QUICKFORM_PROPEL_NO_COLUMNS or
* HTML_QUICKFORM_PROPEL_ALL_COLUMNS
*
* @param string $column column name
* @return void
*
*/
public function setColumnMode($mode)
{
if ($mode != HTML_QUICKFORM_PROPEL_NO_COLUMNS && $mode != HTML_QUICKFORM_PROPEL_ALL_COLUMNS) {
throw new PropelException('HTML_QuickForm_Propel::setColumnMode(): invalid mode passed.');
}
$this->columnMode = $mode;
}
/**
*
* Tell HTML_QuickForm_Propel it should hide this column
* It is now passed like ID instead of somePeer::ID
* The latter is better, but the array_keys of the columns are in ID format and not somePeer::ID
*
* @param string $column column name
* @return void
*
*/
public function hideColumn($column)
{
$this->columnVisibility[$column] = HTML_QUICKFORM_PROPEL_COLUMN_MADE_HIDDEN;
}
/**
*
* Tell HTML_QuickForm_Propel it should show this column
*
* It is now passed like ID instead of somePeer::ID
* The latter is better, but the array_keys of the columns are in ID format and not somePeer::ID
*
* @param string $column column name
* @param string $title Title for the column, not required
* @return void
*/
public function showColumn($column, $title = NULL)
{
$this->columnVisibility[$column] = HTML_QUICKFORM_PROPEL_COLUMN_MADE_VISIBLE;
if ($title !== NULL)
{
$this->setColumnTitle($column, $title);
}
}
/**
*
* assign a title to the column
*
* @param string $column
* @param string $title
* @return void
*/
public function setColumnTitle($column, $title)
{
$this->columnTitles[$column] = $title;
}
/**
*
* returns column's title
*
* @param string $column
* @return void
*/
public function getColumnTitle($column)
{
// TODO: check if $column exists
return (array_key_exists($column, $this->columnTitles))
? $this->columnTitles[$column]
: $column;
}
/**
*
* Try to automatically join all relatedTables.
* NOT IMPLEMENTED
*
* @param boolean $bool
* @return void
*/
public function autoJoin($bool)
{
$this->autoJoin = $bool;
}
/**
* Override this if you don't like the (strtolower) default
*
* @param HTML_QuickForm_Element $el
* @param string $colName
* @return void
*/
protected function addElementId($el, $colName)
{
$el->updateAttributes(array('id'=>strtolower($colName)));
}
/**
*
* Set the default rule typef
* @param string $type
* @return void
*
*/
public function setDefaultRuleType($type)
{
$this->defaultRuleType = $type;
}
/**
*
* UNFINISHED
*
* Probably it would be nice to be able to add this to the schema xml
*
* TODO: further implement multiple columns for the select list
*
* @var colName constant
* @var foreignColName mixed (constant/array of columnName constants)
* @var $seperator string Only used if foreignColName is an array
*/
public function joinColumn($colName, $foreignColName, $seperator = null)
{
if (isset($seperator)) {
$this->seperator = $seperator;
}
$this->joinMap[$colName] = $foreignColName;
}
}

View file

@ -0,0 +1,352 @@
<?
/*
* $Id: Propel.php 1347 2009-12-03 21:06:36Z francois $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://propel.phpdb.org>.
*/
require_once 'Structures/DataGrid.php';
define('STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS', 2);
define('STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS', 3);
define('STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_VISIBLE', 4);
define('STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_HIDDEN', 5);
/**
*
* NOTE: Structures_DataGrid_Propel extends Structures_DataGrid, so all Datagrid functionality is available.
*
* A fictive example:
* // Propel and Propel project classes must be in the include_path
*
* // Propel Class name : Report
* $dg =& new Structures_DataGrid_Propel('Report');
*
* // limit to 10 rows
* $c = new Criteria();
* $c->setLimit(10);
* $dg->setCriteria($c);
*
* // choose what columns must be displayed
* $dg->setColumnMode(STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS);
* $dg->showColumn('ACTIVE');
* $dg->showColumn('TITLE');
* $dg->showColumn('ID');
*
* // generate the datagrid
* $dg->build();
*
* // add two columns to edit the row and checkbox for further operations
* $dg->addColumn(new Structures_DataGrid_Column('', null, null, array('width' => '4%'), null, 'printEditLink()'));
* $dg->addColumn(new Structures_DataGrid_Column('', null, null, array('width' => '1%'), null, 'printCheckbox()'));
*
* // Display the datagrid
* $dg->render();
*
* @author Marc <therebel@free.fr>
* @version $Rev: 1347 $
* @copyright Copyright (c) 2005 Marc: LGPL - See LICENCE
* @package propel.contrib
*/
class Structures_DataGrid_Propel extends Structures_DataGrid {
/**
* Contains column visibility information.
* @var array
* @access private
*/
private $columnVisibility = array();
/**
* The Column visibility mode.
* Possible values:
*
* STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS
* STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS
*
* @var integer
* @access private
*/
private $columnMode;
/**
* String containing the peerName.
* @var string
* @access private
*/
private $peerName;
/**
* String containing the className of the propel Object.
* @var string
* @access private
*/
private $className;
/**
* Criteria of the Select query.
* @var criteria
* @access private
*/
private $criteria;
/**
* List of primary keys
* @var array
* @access public
*/
public $primaryKeys;
/**
*
* The Constructor
*
* Classname is specific to Structures_Datagrid_Propel
*
* The other parameters are needed to construct the parent Structures_DataGrid Class.
*
* @param string className
* @param string limit
* @param string render
*
*/
public function __construct($className = null, $limit = null, $render = DATAGRID_RENDER_HTML_TABLE)
{
include_once $className.'.php';
include_once $className.'Peer'.'.php';
$this->setClassName($className);
$this->setPeerName($className.'Peer'); // Is this always true ?
parent::Structures_DataGrid($limit,null,$render);
// set the default column policy
$this->setColumnMode(STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS);
$this->criteria = new Criteria();
}
/**
*
* Set the criteria for select query
*
* @param Criteria c
*
*/
public function setCriteria(Criteria $c)
{
$this->criteria = $c;
}
/**
*
* Set the class
*
* @param string className
*
*/
public function setClassName($className)
{
$this->className = $className;
}
/**
*
* Get the class name
*
* @return string className
*
*/
public function getClassName()
{
return $this->className;
}
private function setPeerName($peerName)
{
$this->peerName = $peerName;
}
/**
*
* Get the peer name
*
* @return string peerName
*
*/
public function getPeerName()
{
return $this->peerName;
}
/**
*
* Get the visibility of a column
*
* @return boolean true if column is set to hidden
*
*/
public function isColumnHidden($column)
{
if ($this->checkColumn($column, STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_HIDDEN) && $this->columnMode == STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS) {
return true;
}
if (!$this->checkColumn($column, STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_VISIBLE) && $this->columnMode == STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS) {
return true;
}
return false;
}
/**
*
* Check the state of a column
*
* @return boolean true if column is set to state
*
*/
private function checkColumn($column, $state)
{
if (isset($this->columnVisibility[$column])) {
return ($this->columnVisibility[$column] == $state);
} else {
return false;
}
}
/**
*
* Sets the default visibility mode
*
* This must be either:
* STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS or
* STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS
*
* @param string $column column name
* @return void
*
*/
public function setColumnMode($mode)
{
if ($mode != STRUCTURES_DATAGRID_PROPEL_NO_COLUMNS && $mode != STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS) {
throw new PropelException('STRUCTURES_DATAGRID_PROPEL::setColumnMode(): invalid mode passed.');
}
$this->columnMode = $mode;
}
/**
*
* Tell Structures_Datagrid_Propel it should hide this column
* It is now passed like ID instead of somePeer::ID
* The latter is better, but the array_keys of the columns are
* in ID format and not somePeer::ID
*
* @param string $column column name
* @return void
*
*/
public function hideColumn($column)
{
$this->columnVisibility[$column] = STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_HIDDEN;
}
/**
*
* Tell Structures_Datagrid_Propel it should show this column
*
* It is now passed like ID instead of somePeer::ID
* The latter is better, but the array_keys of the columns are in ID format and not somePeer::ID
*
* @param string $column column name
* @return void
*/
public function showColumn($column)
{
$this->columnVisibility[$column] = STRUCTURES_DATAGRID_PROPEL_COLUMN_MADE_VISIBLE;
}
/**
*
* Build the datagrid
*
* @return void
*/
public function build()
{
$mapBuilder = call_user_func(array($this->getPeerName(), 'getMapBuilder'));
$dbMap = $mapBuilder->getDatabaseMap();
$cols = $dbMap->getTable(constant($this->getPeerName()."::TABLE_NAME"))->getColumns();
$stmt = call_user_func(array( $this->getPeerName(), 'doSelectStmt'), $this->criteria);
$dataset = array();
$columns = array();
$this->primaryKeys = array();
$class = $this->getClassName();
while ($row = $stmt->fetch(PDO::FETCH_NUM)) { // use Creole ResultSet methods to iterate over resultset
$obj = new $class();
$obj->hydrate($row);
$row = array();
foreach ($cols as $tmp_id => $col)
{
// save the PK in an array
if ($col->isPrimaryKey()) {
$this->primaryKeys[$col->getColumnName()] = $col->getColumnName();
}
$value = $obj->{'get'.$col->getPhpName()}(null);
// save the row value
$row[$col->getColumnName()] = $value;
// save the list of propel header column name
$columns[$col->getColumnName()] = $col->getColumnName();
}
// add the row to dataset
$dataset[] = $row;
}
$this->bind($dataset);
if ($this->columnMode == STRUCTURES_DATAGRID_PROPEL_ALL_COLUMNS) {
foreach ($columns as $tmp_id => $column) {
if (!$this->isColumnHidden($column)) {
$this->addColumn(new Structures_DataGrid_Column($column, $column, $column, null));
}
}
} else {
foreach ($this->columnVisibility as $column => $visibility) {
if (!$this->isColumnHidden($column)) {
$this->addColumn(new Structures_DataGrid_Column($column, $column, $column, null));
}
}
}
$this->renderer->setTableHeaderAttributes(array('class' => 'title'));
$this->renderer->setTableAttribute('class', 'list');
$this->renderer->sortIconASC = '?';
$this->renderer->sortIconDESC = '?';
}
}