Importing bits and pieces
This is the initial import based on a few files I had around.
This commit is contained in:
commit
871d28cd16
20 changed files with 1994 additions and 0 deletions
73
includes/form/ctrl.inc.php
Normal file
73
includes/form/ctrl.inc.php
Normal file
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
class Ctrl_Form
|
||||
extends Controller
|
||||
{
|
||||
protected $form;
|
||||
|
||||
public function __construct( Form $form )
|
||||
{
|
||||
$this->form = $form;
|
||||
}
|
||||
|
||||
|
||||
protected function getValues( )
|
||||
{
|
||||
$success = true;
|
||||
|
||||
foreach ( $this->form->fields( ) as $field ) {
|
||||
if ( $field === null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$value = $this->getParameter( $field->name( ) , $this->form->method( ) );
|
||||
} catch ( ParameterException $e ) {
|
||||
$value = null;
|
||||
}
|
||||
$field->setFormValue( $value );
|
||||
$vResult = $field->validate( );
|
||||
$success = $success && $vResult;
|
||||
}
|
||||
|
||||
return $success;
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected function applyFormControllers( $page )
|
||||
{
|
||||
foreach ( $this->form->controllers( ) as $controller ) {
|
||||
$result = $controller->handle( $page );
|
||||
if ( $result === null ) {
|
||||
continue;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public function handle( Page $page )
|
||||
{
|
||||
try {
|
||||
$this->getParameter( $this->form->name( ) . '-submit' );
|
||||
} catch ( ParameterException $e ) {
|
||||
return $this->form->view( );
|
||||
}
|
||||
|
||||
if ( ! $this->getValues( ) ) {
|
||||
return $this->form->view( );
|
||||
}
|
||||
|
||||
$cResult = $this->applyFormControllers( $page );
|
||||
if ( $cResult === null ) {
|
||||
return $this->form->view( );
|
||||
}
|
||||
if ( $cResult ) {
|
||||
return $this->form->successURL( );
|
||||
}
|
||||
return $this->form->cancelURL( );
|
||||
}
|
||||
|
||||
}
|
164
includes/form/field.inc.php
Normal file
164
includes/form/field.inc.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
interface FieldValidator
|
||||
{
|
||||
public function validate( $value );
|
||||
}
|
||||
|
||||
|
||||
interface FieldModifier
|
||||
{
|
||||
public function replace( $value );
|
||||
}
|
||||
|
||||
|
||||
final class Field
|
||||
{
|
||||
const MissingError = 'Mandatory';
|
||||
|
||||
private $name;
|
||||
|
||||
private $type;
|
||||
private $options = array( );
|
||||
|
||||
private $description;
|
||||
private $mandatory = true;
|
||||
|
||||
private $valueDefault;
|
||||
private $valueForm;
|
||||
|
||||
private $validator;
|
||||
private $modifier;
|
||||
|
||||
private $errors = array( );
|
||||
|
||||
|
||||
public function __construct( $name , $type )
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
|
||||
public function addOption( $value , $text , $disabled = false )
|
||||
{
|
||||
assert( $this->type === 'select' );
|
||||
assert( ! array_key_exists( $value, $this->options ) );
|
||||
$obj = new stdClass( );
|
||||
$obj->text = $text;
|
||||
$obj->disabled = $disabled;
|
||||
$this->options[ $value ] = $obj;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function options( )
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
|
||||
public function name( )
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function type( )
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
|
||||
public function setDescription( $description )
|
||||
{
|
||||
$this->description = $description;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function description( )
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
|
||||
public function setMandatory( $mandatory )
|
||||
{
|
||||
$this->mandatory = $mandatory;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function mandatory( )
|
||||
{
|
||||
return $this->mandatory;
|
||||
}
|
||||
|
||||
|
||||
public function setModifier( FieldModifier $modifier )
|
||||
{
|
||||
$this->modifier = $modifier;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function setValidator( FieldValidator $validator )
|
||||
{
|
||||
$this->validator = $validator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function setDefaultValue( $default )
|
||||
{
|
||||
$this->valueDefault = $default;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setFormValue( $form )
|
||||
{
|
||||
if ( $this->modifier !== null ) {
|
||||
$form = $this->modifier->replace( $form );
|
||||
}
|
||||
$this->valueForm = $form;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function value( )
|
||||
{
|
||||
return is_null( $this->valueForm )
|
||||
? $this->valueDefault
|
||||
: $this->valueForm;
|
||||
}
|
||||
|
||||
|
||||
public function putError( $error )
|
||||
{
|
||||
$this->errors[ $error ] = 1;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function errors( )
|
||||
{
|
||||
return array_keys( $this->errors );
|
||||
}
|
||||
|
||||
|
||||
public function validate( )
|
||||
{
|
||||
$value = $this->value( );
|
||||
if ( $this->mandatory && ( $value === null || $value == '' ) ) {
|
||||
$this->putError( Loader::Text( Field::MissingError ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->validator !== null ) {
|
||||
$errors = $this->validator->validate( $value );
|
||||
if ( is_array( $errors ) ) {
|
||||
foreach ( $errors as $error ) {
|
||||
$this->putError( $error );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
168
includes/form/form.inc.php
Normal file
168
includes/form/form.inc.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
|
||||
final class Form
|
||||
{
|
||||
|
||||
private $buttonTitle;
|
||||
private $name;
|
||||
private $title;
|
||||
|
||||
private $action;
|
||||
private $method;
|
||||
|
||||
private $cancelURL;
|
||||
private $successURL;
|
||||
|
||||
private $fields = array( );
|
||||
|
||||
private $controllers = array( );
|
||||
|
||||
|
||||
public function __construct( $buttonTitle , $name , $title = null )
|
||||
{
|
||||
$this->buttonTitle = $buttonTitle;
|
||||
$this->title = $title;
|
||||
$this->name = is_null( $name ) ? 'the-form' : $name;
|
||||
$this->action = '?';
|
||||
$this->method = 'POST';
|
||||
}
|
||||
|
||||
|
||||
public function buttonTitle( )
|
||||
{
|
||||
return $this->buttonTitle;
|
||||
}
|
||||
|
||||
public function name( )
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function title( )
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function action( )
|
||||
{
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function method( )
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
public function cancelURL( )
|
||||
{
|
||||
return $this->cancelURL;
|
||||
}
|
||||
|
||||
public function successURL( )
|
||||
{
|
||||
return $this->successURL;
|
||||
}
|
||||
|
||||
public function fields( )
|
||||
{
|
||||
return array_values( $this->fields );
|
||||
}
|
||||
|
||||
public function field( $name )
|
||||
{
|
||||
assert( array_key_exists( $name , $this->fields ) );
|
||||
return $this->fields[ $name ];
|
||||
}
|
||||
|
||||
public function controllers( )
|
||||
{
|
||||
return $this->controllers;
|
||||
}
|
||||
|
||||
|
||||
public function setAction( $action )
|
||||
{
|
||||
$this->action = $action;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMethod( $method )
|
||||
{
|
||||
$this->method = $method;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setURL( $url )
|
||||
{
|
||||
$this->cancelURL = $this->successURL = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCancelURL( $url )
|
||||
{
|
||||
$this->cancelURL = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSuccessURL( $url )
|
||||
{
|
||||
$this->successURL = $url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function addField( Field $field )
|
||||
{
|
||||
assert( ! array_key_exists( $field->name( ) , $this->fields ) );
|
||||
$this->fields[ $field->name( ) ] = $field;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function addSeparator( )
|
||||
{
|
||||
$i = 0;
|
||||
while ( array_key_exists( "sep$i" , $this->fields ) ) {
|
||||
$i ++;
|
||||
}
|
||||
$this->fields[ "sep$i" ] = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function addController( Controller $controller )
|
||||
{
|
||||
if ( is_a( $controller , 'FormAware' ) ) {
|
||||
$controller->setForm( $this );
|
||||
}
|
||||
array_push( $this->controllers , $controller );
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function controller( )
|
||||
{
|
||||
return Loader::Ctrl( 'form' , $this );
|
||||
}
|
||||
|
||||
|
||||
public function view( )
|
||||
{
|
||||
$box = Loader::View( 'box' , $this->title , Loader::View( 'form' , $this ) )
|
||||
->setClass( 'form' );
|
||||
|
||||
if ( $this->cancelURL !== null ) {
|
||||
$box->addButton( BoxButton::create( Loader::Text( 'Cancel' ) , $this->cancelURL )
|
||||
->setClass( 'form-cancel' ) );
|
||||
}
|
||||
|
||||
return $box;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface FormAware
|
||||
{
|
||||
public function setForm( Form $form );
|
||||
}
|
26
includes/form/modifiers.inc.php
Normal file
26
includes/form/modifiers.inc.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
class Modifier_TrimString
|
||||
implements FieldModifier
|
||||
{
|
||||
private $removeDuplicateSpaces;
|
||||
|
||||
|
||||
public function __construct( $removeDuplicateSpaces = true )
|
||||
{
|
||||
$this->removeDuplicateSpaces = $removeDuplicateSpaces;
|
||||
}
|
||||
|
||||
|
||||
public function replace( $value )
|
||||
{
|
||||
if ( $value === null ) {
|
||||
return '';
|
||||
}
|
||||
$value = trim( $value );
|
||||
if ( $this->removeDuplicateSpaces ) {
|
||||
$value = preg_replace( '/\s\s+/' , ' ' , $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
24
includes/form/package.inc.php
Normal file
24
includes/form/package.inc.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
$package[ 'requires' ][] = 'box';
|
||||
|
||||
$package[ 'files' ][] = 'field';
|
||||
$package[ 'files' ][] = 'form';
|
||||
$package[ 'files' ][] = 'view';
|
||||
$package[ 'files' ][] = 'ctrl';
|
||||
$package[ 'files' ][] = 'modifiers';
|
||||
$package[ 'files' ][] = 'validators';
|
||||
|
||||
$package[ 'views' ][] = 'form';
|
||||
$package[ 'ctrls' ][] = 'form';
|
||||
|
||||
$package[ 'extras' ][] = 'Field';
|
||||
$package[ 'extras' ][] = 'FieldModifier';
|
||||
$package[ 'extras' ][] = 'FieldValidator';
|
||||
$package[ 'extras' ][] = 'Form';
|
||||
$package[ 'extras' ][] = 'FormAware';
|
||||
|
||||
$package[ 'extras' ][] = 'Modifier_TrimString';
|
||||
$package[ 'extras' ][] = 'Validator_StringLength';
|
||||
$package[ 'extras' ][] = 'Validator_InArray';
|
||||
$package[ 'extras' ][] = 'Validator_IntValue';
|
99
includes/form/validators.inc.php
Normal file
99
includes/form/validators.inc.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
|
||||
class Validator_StringLength
|
||||
implements FieldValidator
|
||||
{
|
||||
protected $errorPrefix;
|
||||
protected $minLength;
|
||||
protected $maxLength;
|
||||
|
||||
public function __construct( $errorPrefix , $minLength = 0 , $maxLength = null )
|
||||
{
|
||||
assert( $maxLength === null || $maxLength >= $minLength );
|
||||
$this->errorPrefix = $errorPrefix;
|
||||
$this->minLength = $minLength;
|
||||
$this->maxLength = $maxLength;
|
||||
}
|
||||
|
||||
|
||||
public function validate( $value )
|
||||
{
|
||||
$len = strlen( $value );
|
||||
if ( $len < $this->minLength ) {
|
||||
$template = Loader::Text( '%1$s is too short (min. %2$d characters)' );
|
||||
return array( sprintf( $template , $this->errorPrefix , $this->minLength ) );
|
||||
}
|
||||
if ( $this->maxLength !== null && $len > $this->maxLength ) {
|
||||
$template = Loader::Text( '%1$s is too long (max. %2$d characters)' );
|
||||
return array( sprintf( $template , $this->errorPrefix , $this->maxLength ) );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Validator_InArray
|
||||
implements FieldValidator
|
||||
{
|
||||
private $values;
|
||||
private $errorText;
|
||||
|
||||
public function __construct( array $values , $errorText )
|
||||
{
|
||||
$this->values = $values;
|
||||
$this->errorText = $errorText;
|
||||
}
|
||||
|
||||
public function validate( $value )
|
||||
{
|
||||
if ( ! ( empty( $this->values ) || in_array( $value , $this->values ) ) ) {
|
||||
return array( $this->errorText );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Validator_IntValue
|
||||
implements FieldValidator
|
||||
{
|
||||
|
||||
private $invalidText;
|
||||
private $minValue;
|
||||
private $minError;
|
||||
private $maxValue;
|
||||
private $maxError;
|
||||
|
||||
public function __construct( $invalidText )
|
||||
{
|
||||
$this->invalidText = $invalidText;
|
||||
}
|
||||
|
||||
public function setMinValue( $minValue , $minError = null )
|
||||
{
|
||||
assert( $this->maxValue === null || $minValue <= $this->maxValue );
|
||||
$this->minValue = $minValue;
|
||||
$this->minError = ( $minError === null ) ? $this->invalidText : $minError;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxValue( $maxValue , $maxError = null )
|
||||
{
|
||||
assert( $this->minValue === null || $maxValue >= $this->maxValue );
|
||||
$this->maxValue = $maxValue;
|
||||
$this->maxError = ( $maxError === null ) ? $this->invalidText : $maxError;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function validate( $value )
|
||||
{
|
||||
if ( !is_scalar( $value ) || (int) $value != $value ) {
|
||||
return array( $this->invalidText );
|
||||
} else if ( $this->minValue !== null && $value < $this->minValue ) {
|
||||
return array( $this->minError );
|
||||
} else if ( $this->maxValue !== null && $value > $this->maxValue ) {
|
||||
return array( $this->maxError );
|
||||
}
|
||||
}
|
||||
}
|
184
includes/form/view.inc.php
Normal file
184
includes/form/view.inc.php
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
|
||||
class View_Form
|
||||
implements View
|
||||
{
|
||||
protected $form;
|
||||
|
||||
public function __construct( Form $form )
|
||||
{
|
||||
$this->form = $form;
|
||||
}
|
||||
|
||||
|
||||
protected function renderHiddenFields( $prefix )
|
||||
{
|
||||
$result = array( );
|
||||
foreach ( $this->form->fields( ) as $field ) {
|
||||
if ( $field === null || $field->type( ) !== 'hidden' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
array_push( $result , HTML::make( 'input' )
|
||||
->setAttribute( 'type' , 'hidden' )
|
||||
->setAttribute( 'name' , $field->name( ) )
|
||||
->setAttribute( 'value' , HTML::from( $field->value( ) ) )
|
||||
->setAttribute( 'id' , $prefix . $field->name( ) ) );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function renderPasswordField( $field , $prefix )
|
||||
{
|
||||
return HTML::make( 'input' )
|
||||
->setAttribute( 'type' , 'password' )
|
||||
->setAttribute( 'name' , $field->name( ) )
|
||||
->setAttribute( 'id' , $prefix . 'field' )
|
||||
->setAttribute( 'class' , 'form-text-field' );
|
||||
}
|
||||
|
||||
|
||||
protected function renderTextField( $field , $prefix )
|
||||
{
|
||||
return HTML::make( 'input' )
|
||||
->setAttribute( 'type' , 'text' )
|
||||
->setAttribute( 'name' , $field->name( ) )
|
||||
->setAttribute( 'id' , $prefix . 'field' )
|
||||
->setAttribute( 'class' , 'form-text-field' )
|
||||
->setAttribute( 'value' , HTML::from( $field->value( ) ) );
|
||||
}
|
||||
|
||||
|
||||
protected function renderTextArea( $field , $prefix )
|
||||
{
|
||||
return HTML::make( 'textarea' )
|
||||
->setAttribute( 'name' , $field->name( ) )
|
||||
->setAttribute( 'id' , $prefix . 'field' )
|
||||
->setAttribute( 'class' , 'form-text-field' )
|
||||
->appendText( (string) $field->value( ) );
|
||||
}
|
||||
|
||||
|
||||
protected function renderSelectField( $field , $prefix )
|
||||
{
|
||||
$select = HTML::make( 'select' )
|
||||
->setAttribute( 'name' , $field->name( ) )
|
||||
->setAttribute( 'id' , $prefix . 'field' )
|
||||
->setAttribute( 'class' , 'form-select' );
|
||||
|
||||
$selected = $field->value( );
|
||||
foreach ( $field->options( ) as $value => $obj ) {
|
||||
$option = HTML::make( 'option' )
|
||||
->setAttribute( 'value' , $value )
|
||||
->setAttribute( 'disabled' , $obj->disabled ? 'disabled' : null )
|
||||
->appendText( $obj->text );
|
||||
if ( "$value" === "$selected" ) {
|
||||
$option->setAttribute( 'selected' , 'selected' );
|
||||
}
|
||||
$select->appendElement( $option );
|
||||
}
|
||||
return $select;
|
||||
}
|
||||
|
||||
|
||||
protected function renderField( $field , $prefix )
|
||||
{
|
||||
switch ( $field->type( ) ) {
|
||||
|
||||
case 'password':
|
||||
$result = $this->renderPasswordField( $field , $prefix );
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
$result = $this->renderTextField( $field , $prefix );
|
||||
break;
|
||||
|
||||
case 'textarea':
|
||||
$result = $this->renderTextArea( $field , $prefix );
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
$result = $this->renderSelectField( $field , $prefix );
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception( "field " . $field->name() . " has unknown type " . $field->type() );
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
protected function renderVisibleFields( $target , $prefix )
|
||||
{
|
||||
foreach ( $this->form->fields( ) as $field ) {
|
||||
if ( $field === null ) {
|
||||
$target->appendElement( HTML::make( 'hr' ) );
|
||||
continue;
|
||||
}
|
||||
if ( $field->type( ) === 'hidden' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fPrefix = $prefix . $field->name( ) . '-';
|
||||
if ( $field->type( ) === 'html' ) {
|
||||
$target->appendElement( HTML::make( 'dd' )
|
||||
->setAttribute( 'id' , $fPrefix )
|
||||
->setAttribute( 'class' , 'html-section' )
|
||||
->append( $field->value( ) ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
$fClass = 'field' . ( $field->mandatory( ) ? ' mandatory' : '' );
|
||||
$target->appendElement( HTML::make( 'dt' )
|
||||
->setAttribute( 'class' , $fClass )
|
||||
->setAttribute( 'id' , $fPrefix . 'label' )
|
||||
->appendElement( HTML::make( 'label' )
|
||||
->setAttribute( 'for' , $fPrefix . 'field' )
|
||||
->appendText( $field->description( ) ) ) );
|
||||
|
||||
$errors = $field->errors( );
|
||||
if ( !empty( $errors ) ) {
|
||||
foreach ( $errors as $error ) {
|
||||
$target->appendElement( HTML::make( 'dd' )
|
||||
->setAttribute( 'class' , 'form-error' )
|
||||
->appendText( $error ) );
|
||||
}
|
||||
$fClass .= ' erroneous';
|
||||
}
|
||||
|
||||
$target->appendElement( HTML::make( 'dd' )
|
||||
->setAttribute( 'id' , $fPrefix . 'container' )
|
||||
->setAttribute( 'class' , $fClass )
|
||||
->append( $this->renderField( $field , $fPrefix ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function render( )
|
||||
{
|
||||
$name = $this->form->name();
|
||||
$prefix = $name . '-';
|
||||
|
||||
$form = HTML::make( 'form' )
|
||||
->setAttribute( 'name' , $name )
|
||||
->setAttribute( 'id' , $prefix . 'form' )
|
||||
->setAttribute( 'action' , $this->form->action( ) )
|
||||
->setAttribute( 'method' , $this->form->method( ) )
|
||||
->append( $this->renderHiddenFields( $prefix ) )
|
||||
->append( $visibleArea = HTML::make( 'dl' ) );
|
||||
|
||||
$this->renderVisibleFields( $visibleArea , $prefix );
|
||||
$visibleArea->appendElement( HTML::make( 'dt' )
|
||||
->setAttribute( 'class' , 'submit-button' )
|
||||
->setAttribute( 'id' , $prefix . 'submit-container' )
|
||||
->appendElement( HTML::make( 'input' )
|
||||
->setAttribute( 'type' , 'submit' )
|
||||
->setAttribute( 'name' , $prefix . 'submit' )
|
||||
->setAttribute( 'id' , $prefix . 'submit' )
|
||||
->setAttribute( 'value' , $this->form->buttonTitle( ) ) ) );
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue