I'm creating a system form building a form processing an xml. Form Layout is almost the same, so depending on url I will load a different xml that will generate different form.
I use 3 diffrent classes:
- Form manages all form infos (action, enctype, upload dir for files), values (if in update), language and input creation
- Input manages everything concerning Input (name, id, ...)
- Language manages labels
When I create Form obj I create instance of language class (input labels are Language instance key), get values from db and parse XML to create input as Input class instance (passing the input xml object in the constructor). An excerpt for Form class in creating input
if(count($obj->input)):
foreach($obj->input as $input):
$Input = new Input($input);
$val = !empty($this->arValues['normal'][(string)$Input->getname()]) ? $this->arValues['normal'][(string)$Input->getname()] : '';
$Input->setvalue($val);
$label = !empty($input['label']) && !empty($this->Language->getTranslation((string)$input['label'])) ? $this->Language->getTranslation((string)$input['label']) : '';
$Input->setlabel($label);
$Input->setlgTag($lgTag);
$this->arInputs[(string)$Input->getname()] = $Input;
endforeach;
endif;
Xml input can be:
<input type="text" label="label_name" name="name" ...></input>
but also:
<input type="image" label="image_name" name="img" usecaption="true" ...></input>
In the first case no problem, I get my input; in the second case the situation is trickier: - I define the file upload dir in Form, but for input value I'd need it also in input instance (this is pretty easy, but as I define input type in Input class, I would populate a value even when this is not needed) - basing on attribute 'usecaption' I would like to create an input type text for associate caption to image: in fact I'm going to have 2 html inputs (type file & type text) in one xml input (type image) and I lose data as values and language are dfined in Form.
I thought of using Form instance inside input, but as Input instances are defined in Form class, there can be recursive problems, and this is not DRY.
My question is: HOW CAN I PASS AND REUSE SPECIFIC DATA IN INPUT COMING FORM FORM INSTANCE?
Any answer is appreciated... For sure I'm missing something but it's days I'm looping...
CLASSES
#######################################################
#
# class Form
#
# Form management
#
#######################################################
class Form {
private $xmlObj; // xml object used in form construction
private $arInputs; // all the input objects stored
private $Translations; // will contain instance of Translations Class
private $ODB; // class for managing db
private $_ID; // ID of the Elements (if any)
private $tab_name; // table name
private $UploadDir; // upload dir for files
// form properties
public $action = '';
public $method = 'post';
public $enctype = '';
public $arValues = array(); // array for all form values
private $strForm; // string that will contain form html
/*
* __construct
*
* Get xmlObj, translations and element id
*/
public function __construct($xmlObj = NULL, $arTrads = array(), $_ID = 0){
$this->xmlObj = $xmlObj;
$this->Translations = TranslationsManager::getInstance();
$this->ODB = DBObject::getInstance();
$this->_ID = $_ID;
$this->tab_name = !empty($xmlObj['tab_name']) ? $xmlObj['tab_name'] : '';
$this->UploadDir = !empty($xmlObj['upload_dir']) ? $xmlObj['upload_dir'] : '';
$this->action = !empty($xmlObj['action']) ? $xmlObj['action'] : '';
$this->method = !empty($xmlObj['method']) ? $xmlObj['method'] : 'post';
$this->enctype = !empty($xmlObj['enctype']) ? $xmlObj['enctype'] : '';
}
/*
* SetupInputs
*
* I populate array Input
*
*/
public function SetupInputs(){
if(count($this->input)):
foreach($this->input as $input):
$Input = new Input($input); // creo l'oggetto input
endforeach;
endif;
}
/*
* HtmlForm
*
* I echo The form Input
*
*/
public function HtmlForm(){
$this->strForm = '';
if(count($this->xmlObj->input)):
foreach($this->xmlObj->input as $input):
$this->strForm .= $this->arInputs[(string)$input['name']]->htmlIt();
endforeach;
endif;
return $this->strForm;
}
}
#######################################################
#
# class Input
#
# Input management
#
#######################################################
class Input {
private $arAttributes = array(); // Input attributes
private $arOptions = array(); // Input options (to use in input like select, radio, checkbox)
private $strInput; // html
/*
* __construct
*
* Imposto tutti gli attributi dell'input
*/
public function __construct($inputobj = NULL){ // if I don't have any xml obj as parameter, I just create the input object
if($inputobj !== NULL && is_object($inputobj) !== false):
// get attributes if any
if(count($inputobj->attributes())):
foreach($inputobj->attributes() as $key => $val):
$this->arAttributes[(string)$key] = (string)$val;
endforeach;
endif;
// I any option
if(count($inputobj->children())):
foreach($inputobj->children() as $v):
$this->addOption($v);
endforeach;
endif;
// I define id and html of required field
if($this->getAttribute('id') === false && $this->getAttribute('name') !== false) $this->setAttribute('id', $this->getAttribute('name')); // If not specific id I usa name
$this->getAttribute('required') !== false && $this->getAttribute('required') > 0 ? $this->setAttribute('html_required', '*') : $this->setAttribute('html_required', '');
endif;
}
/*
* OVERLOADING
*
* I use to get and set properties from outside
*/
public function __call($prop, $v){
$attr = substr($prop, 3);
$method = substr($prop, 0, 3);
switch($method):
case 'set': return $this->setAttribute($attr, $v[0]); break;
case 'get': return $this->getAttribute($attr); break;
endswitch;
}
/*
* getAttribute - setattribute
*
*
*
*/
private function getAttribute($attr){
return array_key_exists((string)$attr, $this->arAttributes) !== false ? $this->arAttributes[(string)$attr] : false;
}
private function setAttribute($attr, $value){
$this->arAttributes[(string)$attr] = $value;
return true;
}
/*
* addOption
*
* add an option to input checkbox, radio o select
*/
public function addOption($Options){
$this->arOptions[] = $Options;
}
/*
* htmlIt
*
* generate html
*
*/
public function htmlIt(){
// **************************************************************** ISSUE
// I'd like to get the translation using attribute label as parameter: html_label is the correct translation
$this->getAttribute('label') !== false
? $this->setAttribute('html_label', $this->Form->Translations->getTranslations((string)$this->getAttribute('label'))) // <-- HERE I WOULD LIKE TO ACCESS THE Trasnlations INSTANCE IN FORM
: $this->setAttribute('html_label', ''); // ridefinisco la label dell'input sull base della traduzione
switch($this->getAttribute('type')):
case 'texteditor':
return $this->texteditor();
break;
case 'textarea':
return $this->textarea();
break;
case 'radio':
return $this->radio();
break;
case 'img':
return $this->img();
break;
case 'file':
return $this->file();
break;
default:
return $this->text();
endswitch;
}
/*
*
* I CREATE DIFFERENT INPUT TYPE
*
*/
private function text(){
return ' <label'.$this->getAttribute('style').'>'.$this->getAttribute('html_label').$this->getAttribute('html_required').'
<input type="text" name="'.$this->getAttribute('name').'" id="'.$this->getAttribute('id').'" value="'.$this->getAttribute('value').'">
</label>'."\n";
}
private function texteditor(){
return ' <label'.$this->getAttribute('style').'>'.$this->getAttribute('html_label').$this->getAttribute('html_required').'
<textarea name="'.$this->getAttribute('name').'" id="'.$this->getAttribute('id').'" cols="20" rows="5">'.$this->getAttribute('value').'</textarea>
</label>
<script type="text/javascript">
//<!--
CKEDITOR.replace("'.$this->getAttribute('id').'")
//-->
</script>
'."\n";
}
private function textarea(){
return ' <label'.$this->getAttribute('style').'>'.$this->getAttribute('label').$this->getAttribute('html_required').'
<textarea name="'.$this->getAttribute('name').'" id="'.$this->getAttribute('id').'" cols="20" rows="5">'.$this->getAttribute('value').'</textarea>
</label>'."\n";
}
private function radio(){
if(!$this->arOptions || !count($this->arOptions)) return false; // if not any option
$strInput = ' <div class="radio_input"><p>'.$this->getAttribute('html_label').$this->getAttribute('html_required').'</p>'."\n";
foreach($this->arOptions as $Option):
$checked = $this->getAttribute('value') && $this->getAttribute('value') == $Option['value'] ? true : false;
$optLabel = $Option['label'] && strlen($this->Form->Translations->getTranslations($Option['label']))
? $this->Form->Translations->getTranslations($Option['label']) // <-- HERE I WOULD LIKE TO ACCESS THE Translations INSTANCE IN FORM
: '';
if($checked == true):
$strInput .= '
<label class="button label_checked">
<input type="radio" name="'.$this->getAttribute('name').'" id="'.$Option['id'].$lgSuff.'" value="'.$Option['value'].'" checked>
'.$optLabel.'
</label>'."\n";
else:
$strInput .= '
<label class="button">
<input type="radio" name="'.$this->getAttribute('name').'" id="'.$Option['id'].$lgSuff.'" value="'.$Option['value'].'">
'.$optLabel.'
</label>'."\n";
endif;
endforeach;
$strInput .= ' </div>'."\n";
return $strInput;
}
private function img(){
$strFileName = $this->getAttribute('value') !== false && strlen($this->getAttribute('value')) > 0
// ***** I would like to access the Form upload_dir and id
? '<p class="filename"><img src="/file_upload/'.$this->Form->upload_dir.'/'.$this->Form->_ID.'/S_'.$this->getAttribute('value').'"> -
<label class="clear_file"><input type="checkbox" name="remove_'.$this->getAttribute('name').'" id="remove_'.$this->getAttribute('id').'">'.$this->Form->Translations->getTranslations('cancella_file').'</label></p>'
: '';
$strInput = ' <div class="input_file">'."\n";
$strInput .= $strFileName;
$strInput .= '<label class="file_label">'.$this->getAttribute('html_label').$this->getAttribute('html_required').'<br>
<input type="file" name="'.$this->getAttribute('name').'" id="'.$this->getAttribute('id').'">
</label>'."\n";
$strInput .= ' </div>'."\n";
return $strInput;
}
private function file(){
$strFileName = $this->getAttribute('value') !== false && strlen($this->getAttribute('value'))
? '<p class="filename">['.$this->getAttribute('value').'] - <label class="clear_file"><input type="checkbox" name="remove_'.$this->getAttribute('name').'" id="remove_'.$this->getAttribute('id').'">'.
$this->Form->Translations->getTranslations('cancella_file').'</label></p>'
: '';
$strInput = ' <div class="input_file">'."\n";
$strInput .= $strFileName;
$strInput .= '<label class="file_label">'.$this->getAttribute('html_label').$this->getAttribute('html_required').'<br>
<input type="file" name="'.$this->getAttribute('name').'" id="'.$this->getAttribute('id').'">
</label>'."\n";
if($this->getAttribute('caption') !== false):
/************************************************************/
// BIG ISSUE: CREATE INPUT INSIDE ANOTHER
// I need to access Form values
$v = !empty($this->Form->arValues[$this->getAttribute('name').'_caption']) ? $this->Form->arValues[$this->getAttribute('name').'_caption'] : '';
$caption = new Input();
$caption->setAttribute('type', 'text');
$caption->setAttribute('name', (string)$this->getAttribute('name').'_caption');
$caption->setAttribute('id', (string)$this->getAttribute('id').'_caption');
$caption->setAttribute('label', $this->Form->Translations->getTranslations((string)$this->getAttribute('caption')));
$strInput .= $caption->htmlIt();
endif;
$strInput .= ' </div>'."\n";
return $strInput;
}
}
AND XML
<?xml version="1.0" encoding="utf-8"?>
<form tab_name="news" upload_dir="news" enctype="multipart/form-data" action="actionfile.php">
<input type="text" label="title" name="title"></input>
<input type="textarea" label="description" name="description"></input>
<input type="img" label="img_1" name="img_1" prefix="S_,M_" width="300,500" height="300,0" crop_image="Y,N"></input>
</form>