Rendering an action is simple. It is nothing more that a series of echo commands, inside the overridden Render method.
class ActionViewBook extends Action { ... public function Render(){ echo '<h2>' . new Html($this->book->Title) . '</h2>'; ... } ... }
A form in Oxygen always posts its contents back to the same action. Therefore, rendering the form and handing its submissions should be done inside the same Render method. In fact, handling the form should be done just before the rendering. If there is a validation error, then the code will continue to rendering the form again along with the validation messages.
class ActionViewBook extends Action { ... public function Render(){ if ($this->IsPostback()) { // this will check that this is a POST HTTP request coming from the same action. // form handling here (validation and processing) if ($everything_ok) { // success message here maybe ? return; } } echo $this->GetForm(); // this will render the HTML form element with the correct action attribute // form rendering here, along with any possible validation message generated above echo $this->EndForm(); } ... }
A Message is a text that should be displayed to the user, which is classified according to its importance. The importance of the message is defined only by how the used can respond to the message. There are 6 such levels.
The InfoMessage is just a piece of information that the user does not request anything from the user. The user may or may not read the message and continue his or her work. This is the lowest level.
The SuccessMessage is similar to the above because is just a piece of information. However, it is more important, because it gives the user the signal to continue his work.
The WarningMessage is a message that should be read by the user because it may affect its work. However, it is not blocking, and can be ignored.
The QuestionMessage is a message where the user has to respond to a question. It is blocking, because the user is obligated to respond to the question before continuing.
The ErrorMessage is a blocking message that the user cannot do anything to continue. He has to find another way around it.
Finally, the BugMessage is a blocking message that the user cannot even find a way around it because everything he did was correct, but there is some error in the code. This should never happen in a production environment (but it always does, doesn't it).
The MessageControl is a control that displays the message in a nice HTML box. The box will have an icon indicating the message severity, which also defines the color of the background and of the border.
$m = new QuestionMessage( new Lemma('en','Are you sure you want to delete this book?') ); echo new MessageControl( $m );
In addition, there is the MultiMessage, which message consisting of other messages. The severity of a MultiMessage is equal to the one of the most severe of its messages. For example, a message consisting of one info message, two warnings and one error is as severe as an error message. In this case, the MessageControl will display all messages with their icons inside one big box. The color of the background and of the border is determined by the most severe message.
$m = new MultiMessage(); $m[] = new InfoMessage( new Lemma('en','The book has 132 pages.') ); $m[] = new WarningMessage( new Lemma('en','Please use capital letters for the author.') ); $m[] = new ErrorMessage( new Lemma('en','The author of the book was not found in the database.') ); echo new MessageControl( $m );
A Validator is also a MultiMessage, that comes with additional helping methods. The HasPassed method returns true if all the messages in the validator are either InfoMessage or SuccessMessage.
$v = new Validator(); if (empty($book->Title)) $v[] = new WarningMessage( new Lemma('en','The title is a mandatory field.') ); if ($v->HasPassed){ $book->Save(); return; }
The Validator has several methods to aumatically check a condition and add a message, such as Check, CheckMandatory of CheckEmail.
$v_title = new Validator(); $v_author = new Validator(); $v_title->CheckMandatory( $book->Title ); $v_author->CheckMandatory( $book->Author ); $v_author->Check($book->Author==strtoupper($book->Author), new WarningMessage(new Lemma('en','Please use capital letters for the author.')); if ($v_title->HasPassed() && $v_author->HasPassed()) { $book->Save(); return; }
Finally, the ValidatorSet is an array of validators, which is useful to group together all the validators of a form. It will automatically create validator objects as needed.
$v = new ValidatorSet(); $v->Title->CheckMandatory( $book->Title ); $v->Author->CheckMandatory( $book->Author ); $v->Author->Check($book->Author==strtoupper($book->Author), new WarningMessage(new Lemma('en','Please use capital letters for the author.')); if ($v->HasPassed()) { $book->Save(); return; }
This is a typical edit form for a book. It is wrapped inside an AJAX dialog and it contains the form itself and the validation. This example will be refactored in the chapter on Binding to automatically fill and read the form, so it should be considered only as an intermediate step.
class ActionModifyBook extends Action { public function GetDefaultMode(){ return Action::MODE_AJAX_DIALOG; } /** @var Book */ private $book; public function __construct(Book $book){ parent::__construct(); $this->book = $book; } public function GetUrlArgs(){ return array('id'=>$this->book) + parent::GetUrlArgs(); } public static function Make(){ return new static(Book::Pick(Http::$GET['id']->AsID())); } public function IsPermitted(){ return true; } public function Render(){ $v = new ValidatorSet(); $m = Book::Meta(); if ($this->IsPostback()){ // Read the form $this->book->Title = Http::$POST['title']->AsString(); $this->book->Author = Http::$POST['author']->AsString(); // Validate the form $v->Title->CheckMandatory( $this->book->Title ); $v->Author->CheckMandatory( $this->book->Author ); $v->Author->Check($this->book->Author==strtoupper($this->book->Author), Lemma::Pick('MsgUseCapitalLetters')); // Process the form if ($v->HasPassed()) { $this->book->Save(); Oxygen::Refresh(); } } // Render the form echo $this->GetForm(); echo $m->Title->GetLabel(); echo '<br/>' TextBox::Make( 'title', $this->book->Title )->Render(); if (!$v->Title->HasPassed()) echo new MessageControl($v->Title); echo '<br/>' echo $m->Author->GetLabel(); echo '<br/>' TextBox::Make( 'author', $this->book->Author )->Render();; if (!$v->Author->HasPassed()) echo new MessageControl($v->Author); echo '<br/>' ButtonBox::Make()->WithValue( Lemma::Pick('OK') )->WithIsSubmit( true )->Render(); ButtonBox::Make()->WithValue( Lemma::Pick('Cancel') )->WithIsCancel( true )->Render(); echo $this->EndForm(); } }