Location: PHPKode > projects > AModules3 > amodules-3.0.1/lib/Form.php
 * This class implements generic form, which you can actually use without
 * redeclaring it. Just add fields, buttons and use execute method.
 * @author		Romans <hide@address.com>
 * @copyright	See file COPYING
 * @version		$Id$
class Form extends AbstractView {
    public $errors=array();
                            // Here we will have a list of errors occured in the form, when we tried to submit it.
                            //  field_name => error

    public $template_chunks=array();
                            // Those templates will be used when rendering form and fields

    private $data = array(); // This array holds list of values prepared for fields before their initialization. When fields
                            // are initialized they will look into this array to see if there are default value for them.
                            // Afterwards fields will link to $this->data, so changing $this->data['fld_name'] would actually
                            // affect field's value.
                            //  You should use $this->set() and $this->get() to read/write individual field values. You
                            //  should use $this->setStaticSource() to load values from hash
                            //  AAAAAAAAAA: this array is no more!

    public $last_field = null;  // contains reference to last-added filed

    public $bail_out = false;   // if this is true, we won't load data or submit or validate anything.
    public $loaded_from_db = false;     // if true, update() will try updating existing row. if false - it would insert new
    public $onsubmit = false;

    public $dq = null;
    function init(){
         * During form initialization it will go through it's own template and search for lots of small template
         * chunks it will be using. If those chunk won't be in template, it will fall back to default values. This way
         * you can re-define how form will look, but only what you need in particular case. If you don't specify template
         * at all, form will work with default look.

        // commonly replaceable chunks
        $this->grabTemplateChunk('form_line');      // template for form line, must contain field_caption,field_input,field_error
        $this->grabTemplateChunk('field_error');    // template for error code, must contain field_error_str
        $this->grabTemplateChunk('form');           // template for whole form, must contain form_body, form_buttons, form_action,
                                                    //  and form_name

        // ok, other grabbing will be done by field themselves as you will add them to the form.
        // They will try to look into this template, and if you don't have apropriate templates
        // for them, they will use default ones.

        // After init method have been executed, it's safe for you to add controls on the form. BTW, if
        // you want to have default values such as loaded from the table, then intialize $this->data array
        // to default values of those fields.
    function defaultTemplate(){
        return array('form','form');
    function grabTemplateChunk($name){
            $this->template_chunks[$name] = $this->template->cloneRegion($name);
            //return $this->fatal('missing form tag: '.$name);
            // hmm.. i wonder what ? :)

    function addField($type,$name,$caption=null){


        $this->last_field->short_name = $name;

        return $this;
    function addComment($comment){
        $this->add('Text','c'.count($this->elements),'form_body')->set('<tr><td colspan="2" align="center" nowrap>'.$comment.'</td></tr>');
        return $this;
    function addSeparator($separator="<hr>"){
        return $this->addComment($separator);

    function onSubmit(){
        return $this->onsubmit=$this->add('Ajax');

    // Operating with field values
    function get($field){
        if(!isset($this->elements[$field]))throw new BaseException('Trying to get value of not-existing field: '.$field);
        return ($this->elements[$field] instanceof Form_Field)?$this->elements[$field]->get():null;
    function clearData(){
    function setSource($table,$db_fields=null){
            foreach($this->elements as $key=>$el){
                if(!($el instanceof Form_Field))continue;
        $this->dq = $this->api->db->dsql()
        return $this;
    function set($field_or_array,$value=undefined){
        // We use undefined, because 2nd argument of "null" is meaningfull
                foreach($field_or_array as $key=>$val){
                    if(isset($this->elements[$key]) and $this->elements[$key] instanceof Form_Field)$this->set($key,$val);
                return $this;

            throw new BaseException("Trying to set value for non-existant field $field_or_array");
        //if($this->elements[$field_or_array] instanceof Form_Button)echo caller_lookup(0);
        if($this->elements[$field_or_array] instanceof Form_Field) 
        	//throw new BaseException("Form fields must inherit from Form_Field ($field_or_array)");

        return $this;
    function getAllData(){
        foreach($this->elements as $key=>$val){
            if($val instanceof Form_Field){
        return $data;

    // Modifying existing field properties and behavior
    function setProperty($property,$value=null){
        // Add property to field TAG
        return $this;

    function validateField($condition,$msg=''){
                    ($msg?$msg:'Error in ".$this->caption."').'");');
        return $this;
    function validateNotNULL($msg=''){
                    ($msg?$msg:'Please, fill ".$this->caption."').'");');
        return $this;
    function setNotNull($msg=''){
        return $this;

        // TODO: mark field so that it have that red asterisk
    function setNoSave(){
        return $this;
    function setValueList($list){
        return $this;
	function onChange(){
		return $this->last_field->onChange();
	function onKeyPress(){
		return $this->last_field->onKeyPress();

    function addSubmit($label,$name=null){
        $this->last_field = $this->add('Form_Submit',isset($name)?$name:$label)
        return $this;
    function addAjaxButtonAction($label,$name=null){
        return $this->addButton($label,$name);
    function addButton($label,$name=null){

        // Now add the regular button first
        $field = $this->add('Form_Button',isset($name)?$name:$label,'form_buttons')

        // And teach it to use AJAX
        return $field->onclick = $field->add('Ajax')->useProgressIndicator($this->name.'_loading');
    function addCondition($field,$value=null){
        return $this;
    function addConditionFromGET($field,$get_field=null){
        // If GET pases an argument you need to put into your where clause, this is the function you should use.
        return $this->addCondition($field,$_GET[$get_field]);
    function loadData(){
         * This call will be sent to fields, and they will initialize their values from $this->data
            // we actually initialize data from database
            $data = $this->dq->do_getHash();
    function update(){
        if(!$this->dq)throw BaseException("Can't save, query was not initialized");
        foreach($this->elements as $short_name => $element)
        	if($element instanceof Form_Field)if(!is_null($element->get())&&!$element->no_save){
                $this->dq->set($short_name, $element->get());
            // id is present, let's do update
            return $this->dq->do_update();
            // id is not present
            return $this->dq->do_insert();
    function submitted(){
         * Default down-call submitted will automatically call this method if form was submitted
        // We want to give flexibility to our controls and grant them a chance to
        // hook to those spots here.
        // On Windows platform mod_rewrite is lowercasing all the urls.

        if($_GET['submit']!=$this->name)return false;
        if($this->bail_out)return false;


        return empty($this->errors);
    function isSubmitted(){
        // This is alternative way for form submission. After  form is initialized you can call this method. It will
        // hurry up all the steps, but you will have ready-to-use form right away and can make submission handlers
        // easier
        $result = $_POST && $this->submitted();
        return $result;
    function render(){
        // Assuming, that child fields already inserted their HTML code into 'form'/form_body using 'form_line'
        // Assuming, that child buttons already inserted their HTML code into 'form'/form_buttons

        // We don't have anything else to do!
            $this->template->set('form_onsubmit',$this->onsubmit->ajaxFunc('return false')->getString());
    function isClicked($name){
        return $this->api->isClicked($this->name.'_'.$name);
Return current item: AModules3