# documents

title: Introduction
content:
== Introduction ==
This chapter covers issues you need to know before and during installation. It also explains upgrade mechanism.

3333

test test


title: Requirements
content:
Tigermouse requires the server to be capable of:
* PHP 5.2 or newer
* [http://smarty.php.net/download.php|Smarty] template engine
* PDO and PDO drivers are recommended

On client side Tigermouse supports most modern browsers:
* Mozilla Firefox 2 or newer (also other Gecko-based browsers)
* Opera 9 or newer
* Internet Explorer 7 or newer


title: Basic topics
content:
== Basic topics ==

This chapter covers the most fundamental concepts in ''Tigermouse''. You will learn to work with controllers, views, compositing views, using templates, defining action listeners and performing actions. Also validation and data translation subsystems will be presented.


title: Installation
content:
== Installation ==
*TOC*

=== Requirements ===
''Tigermouse'' requires the server to be capable of:
* PHP 5.2 or newer
* [http://smarty.php.net/download.php|Smarty] template engine
* PDO and PDO drivers are recommended

On client side ''Tigermouse'' supports most modern browsers:
* Mozilla Firefox 2 or newer (also other Gecko-based browsers)
* Opera 9 or newer
* Internet Explorer 7 or newer

''Tigermouse'' has also some requirements on the developer who uses it. You need to be really open minded and eager to extend the limits of web development.

=== Download ===
Download stable ''Tigermouse'' release from Sourceforge [http://sourceforge.net/project/showfiles.php?group_id=173530|download page] and unpack it to web server accessible directory.
You can also download Subversion repository, which is development branch with lots of fresh features and bugs. The repository address is:
  https://tigermouse.svn.sourceforge.net/svnroot/tigermouse

=== Installation ===
Once you download ''Tigermouse'' you need to go through few simple steps to make it run. Write access is required to the following directories:
* var/smarty/compile
* var/log
* var/cache
* var/sqlite and var/sqlite/* (optional)
If you run Unix-like operating system go to ''Tigermouse'' directory and execute the following commands:
  chmod 1777 var/smarty/compile
  chmod 1777 var/log
  chmod 1777 var/cache
  chmod 1777 var/sqlite
  chmod 1666 var/sqlite/*
You might need to alter path to ''Smarty'' template engine in ''includes.php'' file.


title: Controllers
content:
== Controllers ==
*TOC*

''Controllers'' (also referred to as ''Application Controllers'') are where all business processing takes place in MVC architecture based applications. Controller is a class derived from ''Ctrl'' class. In ''Tigermouse'' application starts in ''MainCtrl::show()'' method.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		// your application starts here
  	}
  
  }
There is a requirement that file containing controller class must be named with the following convention:
  MainCtrl.class.php
As a consequence, only one controller class per file is allowed.

Controller files can be placed anywhere in the project, however ''ctrl/'' directory is the most natural place.


title: Views
content:
== Views ==
*TOC*

''View'' is an object that can be converted to string recognized by browser. Most views are represented as HTML, but there is also possibility to render RSS, XUL or any other XML document or part of it.

=== Displaying views ===
To display view you need to return it from controller.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$label = new Label();
  		$label->text = 'Hello World';
  		return $label;
  	}
  
  }
Alternatively, its ''update'' method can be called.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$label = new Label();
  		$label->text = 'Hello World';
  		$label->update();
  	}
  
  }

=== Composite views ===
You can have composite views easily using containers. Containers are views that contain other views. To build a composite view using container you need to add one or more views to it.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$label1 = new Label();
  		$label1->text = 'Hello ';
  
  		$label2 = new Label();
  		$label2->text = 'World';
  
  		$container = new View('compView');
  		$container->add($label1);
  		$container->add($label2);
  		return $container;
  	}
  
  }
You can use one of bundled containers such as ''View'', ''HBox'', ''VBox'', ''Menu'', ''Tree'', etc. or write your own using template file.

=== View templates ===
''Tigermouse'' uses ''Smarty'' template engine. Templates are populated with view properties. There are also some special variables defined.

=== View aliases ===
When building an application you need to take care of identifier uniqueness for yourself. This is because there cannot be duplicate identifiers in HTML document. It may be difficult to remember all the identifiers you have used before in your program. So, you are advised to prefix identifiers with container identifier as a convention. This may make identifiers very long and not particular practical for use in templates. In such case you may use views aliases.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$label1 = new Label('MainModule_RootContainer_Label1');
  		$label2 = new Label('MainModule_RootContainer_Label2');
  		$container = new View('MainModule_RootContainer');
  		$container->add($label1, 'label1');
  		$container->add($label2, 'label2');
  		return $container;
  	}
  
  }
In the example above Labels will be registered as label1 and label2 for use in template.
  <div id="{$id}">
    {$label1}
    {$label2}
  </div>
You will learn more about aliases while working with Forms.


title: Listeners and actions
content:
== Listeners and actions ==
Listeners and actions are means to provide interaction in the application.

=== Listeners ===
''Listener'' is an observer that triggers defined action when event occurs. Use listeners to react on user clicks, key press, mouseovers and other well known Javascript events.
Listeners can be defined for views. Arbitrary number of listeners can be defined for each view, however some views restrict types of listeners they work with. This is basic listener definition:
  $label = new Label();
  $label->text = 'Click me';
  $label->addListener(new ClickListener($action));
Listeners are used together with Actions, which will be discussed later.

=== Actions ===
''Action'' is a defined request to be performed on server side. Action definition consists of ''action string'' (mandatory) and argument or array of arguments (optional). Action string is a notation for accessing controllers and their methods. General scheme of action string is:
  [/][directory/[directory/...]]controller/method
Where square brackets indicate optional elements and ellipsis is for multiple elements.
Action string may start with forward slash. If so, the controller file will be looked in the same directory as ''index.php'' file, otherwise it will be looked in ''ctrl/'' directory. Many leading directories may be specified for controller file. The second to the last element is controller name and the last one is controller method.
See example action strings:
  MainCtrl/show
  Login/LoginCtrl/authenticate
  /doc/DocumentationCtrl/index
and example action definitions:
  $a1 = new Action('MainCtrl/show');
  $a2 = new Action('Login/LoginCtrl/Authenticate', array('john_doe', 'secret'));
  $a3 = new Action('/doc/DocumentationCtrl/index', 15);
Running an action can be triggered either directly via its ''run()'' method or indirectly, as a result of triggering a listener. See the complete example of working listener with defined action.
  $label = new Label();
  $label->text = 'Click me';
  $action = new Action('MainCtrl/doSomething');
  $label->addListener(new ClickListener($action));
The two last lines can be merged into one:
  $label->addListener(new ClickListener(new Action('MainCtrl/doSomething')));

=== Aggregating actions ===
To perform more than one action on listener trigger you can either pass actions separated by comma:
  $action1 = new Action('MainCtrl/doSomething');
  $action2 = new Action('MainCtrl/doSomethingElse');
  $label->addListener(new ClickListener($action1, $action2));
or use ''ActionComposite'' object:
  $composite = new ActionComposite(new ArrayObject(
  	new Action('MainCtrl/doSomething'),
  	new Action('MainCtrl/doSomethingElse')
  ));
  $label->addListener(new ClickListener($composite));


title: Intercepting filters
content:
== Intercepting filters ==
Filters allow you to do some processing before and after controller is called. It is a powerful feature, yet not very easy to use.
*TOC*

=== SessionResetFilter ===
This filter is for development only. It reads URL parameters and if ''r=1'' is passed, the PHP session gets reset.

=== LoggingFilter ===
This filter is for development only. It logs requests and parameters to a file. Remember to disable this filter in production environment as it may leas to major security crisis.

=== DuplicateIdGuard ===
This filter is for development only. It checks the DOM tree in browser for duplicated ''id'' attribbutes in HTML elements. Leaving it enabled in production environment may lead to poor performance on client side.

=== FocusFilter ===
This filter allows you to focus arbitrary element after response is sent. Useful in forms validation, when you need to focus element which failed validation.

=== ViewCachingFilter ===
Powerful Views cache.

=== RoleBasedAccessControlFilter ===
Powerful access guard.


title: Updating views
content:
== Updating views ==
*TOC*

=== Updating single view ===
Partial page update is probably the most often use of Ajax. With ''Tigermouse'' this is very easy. What you need to do is just to return a view from controller. Element with ''id'' attribute identical as the view you returned will be replaced.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$button = new Button('InteractiveWidget');
  		$button->text = 'Click me!';
  		$button->addListener(new ClickListener(new Action('MainCtrl/click')));
  		return $button;
  	}
  
  	public function click() {
  		$label = new Label('InteractiveWidget');
  		$label->text = 'You clicked me!';
  		return $label;
  	}
  
  }
In the example above the button has a listener added which will trigger action ''MainCtrl/click'' on mouse click. Controller method ''click()'' returns a view that has the same name as button, which results in button being replaced/updated with the label.

=== Updating multiple views ===
To update multiple views you need to use view's ''update()'' method instead of returning it from controller. Call ''update()'' on as many views you wish to update.


# documents_versions

content:
== Introduction ==
This chapter covers issues you need to know before and during installation. It also explains upgrade mechanism.

2222


content:
== Introduction ==
This chapter covers issues you need to know before and during installation. It also explains upgrade mechanism.

3333


changes: 'Aggregating actions' section added
content:
== Listeners and actions ==
Listeners and actions are means to provide interaction in the application.
*TOC*

=== Listeners ===
''Listener'' is an observer that triggers defined action when event occurs. Use listeners to react on user clicks, key press, mouseovers and other well known Javascript events.
Listeners can be defined for views. Arbitrary number of listeners can be defined for each view, however some views restrict types of listeners they work with. This is basic listener definition:
  $label = new Label();
  $label->text = 'Click me';
  $label->addListener(new ClickListener($action));
Listeners are used together with Actions, which will be discussed later.

=== Actions ===
''Action'' is a defined request to be performed on server side. Action definition consists of ''action string'' (mandatory) and argument or array of arguments (optional). Action string is a notation for accessing controllers and their methods. General scheme of action string is:
  [/][directory/[directory/...]]controller/method
Where square brackets indicate optional elements and ellipsis is for multiple elements.
Action string may start with forward slash. If so, the controller file will be looked in the same directory as ''index.php'' file, otherwise it will be looked in ''ctrl/'' directory. Many leading directories may be specified for controller file. The second to the last element is controller name and the last one is controller method.
See example action strings:
  MainCtrl/show
  Login/LoginCtrl/authenticate
  /doc/DocumentationCtrl/index
and example action definitions:
  $a1 = new Action('MainCtrl/show');
  $a2 = new Action('Login/LoginCtrl/Authenticate', array('john_doe', 'secret'));
  $a3 = new Action('/doc/DocumentationCtrl/index', 15);
Running an action can be triggered either directly via its ''run()'' method or indirectly, as a result of triggering a listener. See the complete example of working listener with defined action.
  $label = new Label();
  $label->text = 'Click me';
  $action = new Action('MainCtrl/doSomething');
  $label->addListener(new ClickListener($action));
The two last lines can be merged into one:
  $label->addListener(new ClickListener(new Action('MainCtrl/doSomething')));

=== Aggregating actions ===
To perform more than one action on listener trigger you can either pass actions separated by comma:
  $action1 = new Action('MainCtrl/doSomething');
  $action2 = new Action('MainCtrl/doSomethingElse');
  $label->addListener(new ClickListener($action1, $action2));
or use ''ActionComposite'' object:
  $composite = new ActionComposite(new ArrayObject(
  	new Action('MainCtrl/doSomething'),
  	new Action('MainCtrl/doSomethingElse')
  ));
  $label->addListener(new ClickListener($composite));


changes: Initial document
content:
== Keyboard shortcuts ==
*TOC*

=== Global shortcuts ===
''Tigermouse'' allows you to define global application keyboard shortcuts. Shortcuts trigger actions as shown in the example below.
  $a = new Action('AboutCtrl/displayCreditst');
  HotKey($a, 'Ctrl+i');
To unregister global shortcut type:
  HotKey('Ctrl+i');

=== Keyboard shortcuts ===
In the example above there is a descriptive way of defining shortcuts. You can type key name or their combinations. See some examples:
  Enter
  Space
  Esc
  1
  F1
  a
  Ctrl+X
  Alt+PgUp
  Shift+Alt+Ctrl+Space

=== Keyboard listeners ===
There are keyboard events listeners available in ''Tigermouse''.
  $i = new Input('test');
  $i->addListener(new KeyPressListener(new Action('FooCtrl/bar'), 'Esc'));
Another interesting listener is ''StopTypingListener''. It triggers action on typing inactivity after given delay.
  $search = new Input('search');
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $search->addListener(new StopTypingListener($a, 400));
This will run action after 400ms of keyboard inactivity. To prevent sending requests when input field is empty you may employ a little hack using behaviours, actions, value readers and the fact, that they all are represented by Javascript.
  $search = new Input('search');
  $r = $search->valueReader();
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $b = new Behaviour("if ($r != '') $a"); // *
  $search ->addListener($b, 400);
The code passed to behaviour object in line marked with * is a Javascript that performs action ''$a'' if input field value reader is not an empty string.


changes: typo
content:
== Keyboard shortcuts ==
*TOC*

=== Global shortcuts ===
''Tigermouse'' allows you to define global application keyboard shortcuts. Shortcuts trigger actions as shown in the example below.
  $a = new Action('AboutCtrl/displayCreditst');
  HotKey($a, 'Ctrl+i');
To unregister global shortcut type:
  HotKey('Ctrl+i');

=== Keyboard shortcuts ===
In the example above there is a descriptive way of defining shortcuts. You can type key name or their combinations. See some examples:
  Enter
  Space
  Esc
  1
  F1
  a
  Ctrl+X
  Alt+PgUp
  Shift+Alt+Ctrl+Space

=== Keyboard listeners ===
There are keyboard events listeners available in ''Tigermouse''.
  $i = new Input('test');
  $i->addListener(new KeyPressListener(new Action('FooCtrl/bar'), 'Esc'));
Another interesting listener is ''StopTypingListener''. It triggers action on typing inactivity after given delay.
  $search = new Input('search');
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $search->addListener(new StopTypingListener($a, 400));
This will run action after 400ms of keyboard inactivity. To prevent sending requests when input field is empty you may employ a little hack using behaviours, actions, value readers and the fact, that they all are represented by Javascript.
  $search = new Input('search');
  $r = $search->valueReader();
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $b = new Behaviour("if ($r != '') $a"); // *
  $search->addListener($b, 400);
The code passed to behaviour object in line marked with * is a Javascript that performs action ''$a'' if input field value reader is not an empty string.


changes: 'StopTypingListener' added
content:
== Keyboard shortcuts ==
*TOC*

=== Global shortcuts ===
''Tigermouse'' allows you to define global application keyboard shortcuts. Shortcuts trigger actions as shown in the example below.
  $a = new Action('AboutCtrl/displayCreditst');
  HotKey($a, 'Ctrl+i');
To unregister global shortcut type:
  HotKey('Ctrl+i');

=== Keyboard shortcuts ===
In the example above there is a descriptive way of defining shortcuts. You can type key name or their combinations. See some examples:
  Enter
  Space
  Esc
  1
  F1
  a
  Ctrl+X
  Alt+PgUp
  Shift+Alt+Ctrl+Space

=== Keyboard listener ===
There are keyboard events listeners available in ''Tigermouse''.
  $i = new Input('test');
  $i->addListener(new KeyPressListener(new Action('FooCtrl/bar'), 'Esc'));

=== Keyboard inactivity listener ===
Another interesting listener is ''StopTypingListener''. It triggers action on typing inactivity after given delay.
  $search = new Input('search');
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $search->addListener(new StopTypingListener($a, 400));
This will run action after 400ms of keyboard inactivity.
==== Improving StopTypingListener ====
To prevent sending requests when input field is empty you may employ a little hack using behaviours, actions, value readers and the fact, that they all are represented by Javascript.
  $search = new Input('search');
  $r = $search->valueReader();
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $b = new Behaviour("if ($r != '') $a"); // *
  $search->addListener($b, 400);
The code passed to behaviour object in line marked with * is a Javascript that performs action ''$a'' if input field value reader is not an empty string.
==== Ceasing StopTypingListener ====
If you want to cancel listener countdown from server side just type:
  StopTypingListener::cease();
This will prevent listener from running delayed action after scheduled time.


changes: Keyboard shortcuts explained, first.
content:
== Keyboard shortcuts ==
*TOC*

=== Keyboard shortcuts ===
''Tigermouse'' allows you to use friendly keyboard shortcuts strings. Just type key name or their combinations. See some examples:
  Enter
  Space
  Esc
  1
  F1
  a
  Ctrl+X
  Alt+PgUp
  Shift+Alt+Ctrl+Space

=== Global shortcuts ===
Global application keyboard shortcuts can be easily defined. Shortcuts trigger actions as shown in the example below.
  $a = new Action('AboutCtrl/displayCreditst');
  HotKey::register($a, 'Ctrl+i');
To unregister global shortcut type:
  HotKey::unregister('Ctrl+i');

=== Keyboard listener ===
There are keyboard events listeners available in ''Tigermouse''.
  $i = new Input('test');
  $i->addListener(new KeyPressListener(new Action('FooCtrl/bar'), 'Esc'));

=== Keyboard inactivity listener ===
Another interesting listener is ''StopTypingListener''. It triggers action on typing inactivity after given delay.
  $search = new Input('search');
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $search->addListener(new StopTypingListener($a, 400));
This will run action after 400ms of keyboard inactivity.
==== Improving StopTypingListener ====
To prevent sending requests when input field is empty you may employ a little hack using behaviours, actions, value readers and the fact, that they all are represented by Javascript.
  $search = new Input('search');
  $r = $search->valueReader();
  $a = new Action('SearchCtrl/doSearch', $search->valueReader());
  $b = new Behaviour("if ($r != '') $a"); // *
  $search->addListener($b, 400);
The code passed to behaviour object in line marked with * is a Javascript that performs action ''$a'' if input field value reader is not an empty string.
==== Ceasing StopTypingListener ====
If you want to cancel listener countdown from server side just type:
  StopTypingListener::cease();
This will prevent listener from running delayed action after scheduled time.


changes: Initial import
content:
== Forms ==
*TOC*

=== Reading values from single field ===
To pass form field value to controller you need to use its ''Value Reader''. See how to use value readers in Action objects.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$login = new Input('login'));
  		$ok = new Button();
  		$ok->addListener(
  			new ClickListener(
  				new Action('MainCtrl/login', $login->valueReader())
  			)
  		);
  		$v = new View();
  		$v->add($login);
  		$v->add($ok);
  		return $v;
  	}
  
  }

==== Receiving values from single field ====
Single field values are passed as regular parameters. Add the following method to the class above to display alert box with passed parameter.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		...
  	}
  	
  	public function login($loginName) {
  		$this->response->alert($loginName);
  	}
  
  }

=== Reading values from whole form ===
To pass a set of field values use Form's value reader.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$f = new Form();
  		$f->add(new Input('login'));
  		$f->add(new Input('password'));
  		$ok = new Button();
  		$ok->addListener(
  			new ClickListener(
  				new Action('MainCtrl/login', $f->valueReader())
  			)
  		);
  		$f->add($ok);
  		return $f;
  	}
  
  }

==== Receiving values from forms ====
Fields values read with Form's value reader are passed as ''FormContext'' objects. Form context is an object with public properties that match form elements identifiers (or aliases).
Add the following method to the example above:
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		...
  	}
  	
  	public function login(FormContext $cx) {
  		$this->response->alert("Hello {$cx->login}, I see your password is {$cx->password}");
  	}
  
  }

=== Mixing single values and form values ===
You can pass arbitrary number of parameters and mix single field values with form values. You can even pass more than one form values (e.g. for two different forms).


content:
== Intercepting filters ==
Filters allow you to do some processing before and after controller is called. It is a powerful feature, yet not very easy to use.
*TOC*

=== The interface ===
A class that implements IncerteptingFilter interface must implement two methods:
  public function preProcess(RequestContext $request, ResponseContext $response);
  public function postProcess(RequestContext $request, ResponseContext $response);
Using filter you can influence on RequestContext and ResponseContext objects.

=== Built-in filters ===
The filters described below are provided with Tigermouse by default. Some of theme are useful in development only and '''may cause severe security risk''' if enabled on production server.

==== SessionResetFilter ====
This filter is for development only. It reads URL parameters and if ''r=1'' is passed, the PHP session gets reset.

==== LoggingFilter ====
This filter is for development only. It logs requests and parameters to a file. Remember to disable this filter in production environment. Leaving it enabled may lead to major security crisis as this filter can log passwords sent in HTTP request.

==== DuplicateIdGuard ====
This filter is for development only. It checks the DOM tree in browser for duplicated ''id'' attribbutes in HTML elements. Leaving it enabled in production environment may cause poor performance on client side.

==== FocusFilter ====
This filter allows you to focus arbitrary element after response is sent. Useful in forms validation, when you need to focus element which failed validation.

==== ViewCachingFilter ====
Powerful Views cache.

==== RoleBasedAccessControlFilter ====
Powerful access guard.


changes: Validation subsystem
content:
== Forms ==
*TOC*

=== Reading values from single field ===
To pass form field value to controller you need to use its ''Value Reader''. See how to use value readers in Action objects.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$login = new Input('login'));
  		$ok = new Button();
  		$ok->addListener(
  			new ClickListener(
  				new Action('MainCtrl/login', $login->valueReader())
  			)
  		);
  		$v = new View();
  		$v->add($login);
  		$v->add($ok);
  		return $v;
  	}
  
  }

==== Receiving values from single field ====
Single field values are passed as regular parameters. Add the following method to the class above to display alert box with passed parameter.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		...
  	}
  	
  	public function login($loginName) {
  		$this->response->alert($loginName);
  	}
  
  }

=== Reading values from whole form ===
To pass a set of field values use Form's value reader.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		$f = new Form();
  		$f->add(new Input('login'));
  		$f->add(new Input('password'));
  		$ok = new Button();
  		$ok->addListener(
  			new ClickListener(
  				new Action('MainCtrl/login', $f->valueReader())
  			)
  		);
  		$f->add($ok);
  		return $f;
  	}
  
  }

==== Receiving values from forms ====
Fields values read with Form's value reader are passed as ''FormContext'' objects. Form context is an object with public properties that match form elements identifiers (or aliases).
Add the following method to the example above:
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		...
  	}
  	
  	public function login(FormContext $cx) {
  		$this->response->alert("Hello {$cx->login}, I see your password is {$cx->password}");
  	}
  
  }

=== Mixing single values and form values ===
You can pass arbitrary number of parameters and mix single field values with form values. You can even pass more than one form values (e.g. for two different forms).

=== Validation ===
''Tigermouse'' provides validation subsystem for use with forms or single fields. See how validator can be defined in connection with form shown above.
  class MainCtrl extends Ctrl {
  
  	public function show() {
  		...
  	}
  	
  	public function login(FormContext $cx) {
  		$f = $this->show();
  		$v = new CompositeValidator();
  		$v->add(new LoginNameValidator($cx->login, $f->login));
  		$v->add(new LengthValidator($cx->passwd, $f->passwd, 1, 60));
  		if (!$v->valid()) {
  			return;
  		}
  		$this->response->alert("Hello {$cx->login}, I see your password is {$cx->password}");
  	}
  
  }
''CompositeValidator'' is used to define multiple validation rules. Many rules can be added for each form field or form context value. In this case ''LoginNameValidator'' and ''LengthValidator'' are used. Method ''valid()'' can set error message on field that failed validation.

==== Focusing invalid field ====
There is easy way to automatically focus the first field that failed validation. Use ''FocusCompositeValidator'' instead of ''CompositeValidator'' and cursor will be placed in the first field with error message set.
If you wish to focus arbitrary field manually use ''FocusFilter'' intercepting filter:
  FocusFilter::setFocus($f->login);
This will focus login input field from the form above.

==== Custom validators ====
Method ''valid()'' is the only one in ''IValidator'' interface, however it is convenient to derive your class from ''Validator'' superclass. Take a look at example ''PositiveIntegerValidator'' class that will success only on positive integers.
  class PositiveIntegerValidator extends Validator {
  	
  	public function valid() {
  		if (!parent::valid()) {
  			return false;
  		}
  		if (!is_numeric($this->value) or (int)$this->value != $this->value or $this->value < 0) {
  			$this->view->errorMessage('Positive integer required');
  			return false;
  		}
  		return true;

  	}
  	
  }
It is important to call superclass ''valid()'' method as it clears previous errors.


