Skip to content

Instantly share code, notes, and snippets.

@Deathnerd
Last active March 11, 2016 21:43
Show Gist options
  • Save Deathnerd/22bc289a343f472de825 to your computer and use it in GitHub Desktop.
Save Deathnerd/22bc289a343f472de825 to your computer and use it in GitHub Desktop.
A rough example of what using annotations to control form validation and rendering could look like
<?php
/**
* Must annotate as a Form. This can also hold
* metadata about the form later on. In this example, if csrf is
* set to true, it enables csrf protection automatically.
*
* It's also very trivial to implement localization and have it automatically
* localize things such as Label texts at render time
*
* See https://github.com/Deathnerd/php-wtforms/tree/master/src for work I've already done
* @Form(csrf=true)
*/
class RegistrationForm extends Form
{
/**
* This property is annotated as a <select> field and will render
* with the given choices. If multiple is true, will render as <select multiple>
* @Fields\Select(label="Prefix", choices=["Mr.", "Mrs.", "Ms."], multiple=false)
*/
public $prefix;
/**
* This will render according to the __call() method defined on \My\Custom\Widget
* @Fields\StringField(label="First Name", widget="\My\Custom\Widget")
* This validator will trigger if the input length goes over 25 characters, and will
* have the message defined available for echoing to the user
* @Validator\Length(max=25, message="Your first name is too long. Got a nickname?")
* @Validator\InputRequired(message="What is your first name?")
*/
public $first_name;
/**
* This will default to rendering as an <input type="text"> element
* @Fields\StringField(label="Last Name")
*/
public $last_name;
/**
* This will render as an <input type="email"> and may also have some special rules
* associated with it
* @Fields\HTML5\EmailField(label="Your Email")
* @Validator\Email(message="Please use a valid email")
*/
public $email;
/**
* @Validator\InputRequired(message="You must be over 18 to use this site")
* @Fields\BooleanField(label="Are you over 18?")
*/
public $over_18;
/**
* @Fields\StringField(label="Username")
* @Validator\Length(min=4, max=25, message="Your user name must be between 4 and 25 characters long")
*/
public $username;
/**
* @Fields\PasswordField(label="Password")
*/
public $password;
/**
* @Fields\PasswordField(label="Confirm Password")
* @Validator\EqualTo(field="password", message="Passwords must match!")
*/
public $confirm_password;
/**
* @Fields\HTML5\DateTimeField(label="Your Birthday", format="m-d-Y")
*/
public $birthday;
}
// Assuming such method exists, get a user object from the DB
$user = DB::getUser();
// First argument is an associative array of data corresponding to
// fields on the form object. Options array (supporting more than you see here)
// may contain an `obj` element containing an object with data that
// can be used as data for fields if it is not found in the first
// argument
$form = new RegistrationForm($_POST, ["obj" => $user]);
// Default method Form::validate will find each Field annotated property
// and check against a validator if it was annotated with it. Returns
// true if no validation errors occurred, otherwise returns false and
// holds validation error messages in the $errors array on the form
if ($_POST && $form->validate()) {
$form->populate_object($user);
$user->save();
header("Location: index.php");
exit;
}
// Takes the model and converts all properties that are annotated as fields
// and associated labels into actual objects that can be manipulated on the
// view. Also carries over the errors array
$view_form = Form::createViewForm($form);
// Render-time overriding of default attributes
$view_form->setDefaultLabelAttr(['class' => "form-label"]);
// Supporting Callable functions as well
$view_form->setDefaultFieldAttr(['class' => "form-control", "data-form-stuff" => function ($field) {
return "foobar: " . $field->name;
}]);
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example Form</title>
</head>
<body>
<ul id="form-errors">
<? foreach ($view_form->errors as $error) { ?>
<li><?= $error ?></li>
<? } ?>
</ul>
<form action="<?= $_SERVER['PHP_SELF'] ?>">
<!-- Automatically generated if the Form is set to enable CSRF in the class annotation -->
<?= $view_form->csrf_token ?>
<!-- Echoing each property generates valid, escaped HTML -->
<?= $view_form->prefix->label ?><!--<label class="form-label">Prefix</label>-->
<?= $view_form->prefix ?><!--<input type="text" name="prefix" data-form-stuff="foobar">-->
<!-- or calling properties as methods allows for HTML attribute overriding at render time -->
<?= $view_form->prefix->label(["for" => "prefix_input"]) ?><!--<label for="prefix_input" class="form-label">Prefix</label>-->
<?= $view_form->prefix(["id" => "prefix_input"]) ?><!--<input type="text" name="prefix" id="prefix_input" data-form-stuff="foobar">-->
<!-- Fields also available through an iterator -->
<? foreach ($view_form->fields as $field) {
echo $field->label . " " . $field;
} ?>
<button type="submit">Register!</button>
</form>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment