Commit 147b3155 by Qiang Xue

Added contact page. Fixed various form bugs.

parent 0d182ace
...@@ -15,4 +15,7 @@ return array( ...@@ -15,4 +15,7 @@ return array(
'bundles' => require(__DIR__ . '/assets.php'), 'bundles' => require(__DIR__ . '/assets.php'),
), ),
), ),
'params' => array(
'adminEmail' => 'admin@example.com',
),
); );
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
use yii\web\Controller; use yii\web\Controller;
use app\models\LoginForm; use app\models\LoginForm;
use app\models\ContactForm;
class SiteController extends Controller class SiteController extends Controller
{ {
...@@ -14,7 +15,7 @@ class SiteController extends Controller ...@@ -14,7 +15,7 @@ class SiteController extends Controller
{ {
$model = new LoginForm(); $model = new LoginForm();
if ($this->populate($_POST, $model) && $model->login()) { if ($this->populate($_POST, $model) && $model->login()) {
Yii::$app->getResponse()->redirect(array('site/index')); Yii::$app->response->redirect(array('site/index'));
} else { } else {
echo $this->render('login', array( echo $this->render('login', array(
'model' => $model, 'model' => $model,
...@@ -30,7 +31,15 @@ class SiteController extends Controller ...@@ -30,7 +31,15 @@ class SiteController extends Controller
public function actionContact() public function actionContact()
{ {
echo $this->render('contact'); $model = new ContactForm;
if ($this->populate($_POST, $model) && $model->contact(Yii::$app->params['adminEmail'])) {
Yii::$app->session->setFlash('contact', 'Thank you for contacting us. We will respond to you as soon as possible.');
Yii::$app->response->refresh();
} else {
echo $this->render('contact', array(
'model' => $model,
));
}
} }
public function actionAbout() public function actionAbout()
......
<?php
namespace app\models;
use yii\base\Model;
/**
* ContactForm is the model behind the contact form.
*/
class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
public $verifyCode;
/**
* @return array the validation rules.
*/
public function rules()
{
return array(
// name, email, subject and body are required
array('name, email, subject, body', 'required'),
// email has to be a valid email address
array('email', 'email'),
// verifyCode needs to be entered correctly
//array('verifyCode', 'captcha', 'allowEmpty' => !Captcha::checkRequirements()),
);
}
/**
* @return array customized attribute labels
*/
public function attributeLabels()
{
return array(
'verifyCode' => 'Verification Code',
);
}
/**
* Sends an email to the specified email address using the information collected by this model.
* @param string $email the target email address
* @return boolean whether the model passes validation
*/
public function contact($email)
{
if ($this->validate()) {
$name = '=?UTF-8?B?' . base64_encode($this->name) . '?=';
$subject = '=?UTF-8?B?' . base64_encode($this->subject) . '?=';
$headers = "From: $name <{$this->email}>\r\n" .
"Reply-To: {$this->email}\r\n" .
"MIME-Version: 1.0\r\n" .
"Content-type: text/plain; charset=UTF-8";
mail($email, $subject, $this->body, $headers);
return true;
} else {
return false;
}
}
}
\ No newline at end of file
<?php <?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace app\models; namespace app\models;
...@@ -11,8 +6,7 @@ use Yii; ...@@ -11,8 +6,7 @@ use Yii;
use yii\base\Model; use yii\base\Model;
/** /**
* @author Qiang Xue <qiang.xue@gmail.com> * LoginForm is the model behind the login form.
* @since 2.0
*/ */
class LoginForm extends Model class LoginForm extends Model
{ {
...@@ -20,16 +14,25 @@ class LoginForm extends Model ...@@ -20,16 +14,25 @@ class LoginForm extends Model
public $password; public $password;
public $rememberMe = true; public $rememberMe = true;
/**
* @return array the validation rules.
*/
public function rules() public function rules()
{ {
return array( return array(
array('username', 'required'), // username and password are both required
array('password', 'required'), array('username, password', 'required'),
// password is validated by validatePassword()
array('password', 'validatePassword'), array('password', 'validatePassword'),
// rememberMe must be a boolean value
array('rememberMe', 'boolean'), array('rememberMe', 'boolean'),
); );
} }
/**
* Validates the password.
* This method serves as the inline validation for password.
*/
public function validatePassword() public function validatePassword()
{ {
$user = User::findByUsername($this->username); $user = User::findByUsername($this->username);
...@@ -38,11 +41,15 @@ class LoginForm extends Model ...@@ -38,11 +41,15 @@ class LoginForm extends Model
} }
} }
/**
* Logs in a user using the provided username and password.
* @return boolean whether the user is logged in successfully
*/
public function login() public function login()
{ {
if ($this->validate()) { if ($this->validate()) {
$user = User::findByUsername($this->username); $user = User::findByUsername($this->username);
Yii::$app->getUser()->login($user, $this->rememberMe ? 3600*24*30 : 0); Yii::$app->user->login($user, $this->rememberMe ? 3600*24*30 : 0);
return true; return true;
} else { } else {
return false; return false;
......
...@@ -41,6 +41,8 @@ $this->registerAssetBundle('app'); ...@@ -41,6 +41,8 @@ $this->registerAssetBundle('app');
<?php echo $content; ?> <?php echo $content; ?>
<hr>
<div class="footer"> <div class="footer">
<p>&copy; My Company <?php echo date('Y'); ?></p> <p>&copy; My Company <?php echo date('Y'); ?></p>
<p> <p>
......
...@@ -5,4 +5,11 @@ use yii\helpers\Html; ...@@ -5,4 +5,11 @@ use yii\helpers\Html;
*/ */
$this->title = 'About'; $this->title = 'About';
?> ?>
<h1><?php echo Html::encode($this->title); ?></h1> <h1><?php echo Html::encode($this->title); ?></h1>
\ No newline at end of file
<p>
This is the About page. You may modify the following file to customize its content:
</p>
<code><?php echo __FILE__; ?></code>
...@@ -8,3 +8,20 @@ use yii\helpers\Html; ...@@ -8,3 +8,20 @@ use yii\helpers\Html;
$this->title = 'Contact'; $this->title = 'Contact';
?> ?>
<h1><?php echo Html::encode($this->title); ?></h1> <h1><?php echo Html::encode($this->title); ?></h1>
<p>Please fill out the following fields:</p>
<?php $form = $this->beginWidget('yii\widgets\ActiveForm', array(
'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
)); ?>
<?php echo $form->field($model, 'name')->textInput(); ?>
<?php echo $form->field($model, 'email')->textInput(); ?>
<?php echo $form->field($model, 'subject')->textInput(); ?>
<?php echo $form->field($model, 'body')->textArea(array('rows' => 6)); ?>
<div class="control-group">
<div class="controls">
<?php echo Html::submitButton('Submit', null, null, array('class' => 'btn btn-primary')); ?>
</div>
</div>
<?php $this->endWidget(); ?>
\ No newline at end of file
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
$this->title = 'Welcome'; $this->title = 'Welcome';
?> ?>
<div class="jumbotron"> <div class="jumbotron">
<h1>Marketing stuff!</h1> <h1>Welcome!</h1>
<p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Fusce dapibus, tellus ac cursus <p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Fusce dapibus, tellus ac cursus
commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p> commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
<a class="btn btn-large btn-success" href="http://www.yiiframework.com">Get started today</a> <a class="btn btn-large btn-success" href="http://www.yiiframework.com">Get started with Yii</a>
</div> </div>
<hr> <hr>
...@@ -45,5 +45,3 @@ $this->title = 'Welcome'; ...@@ -45,5 +45,3 @@ $this->title = 'Welcome';
</div> </div>
</div> </div>
<hr>
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
settings.validationUrl = $form.attr('action'); settings.validationUrl = $form.attr('action');
} }
$.each(attributes, function (i) { $.each(attributes, function (i) {
attributes[i] = $.extend({}, attributeDefaults, this); attributes[i] = $.extend({value: getValue($form, this)}, attributeDefaults, this);
}); });
$form.data('yiiActiveForm', { $form.data('yiiActiveForm', {
settings: settings, settings: settings,
...@@ -121,7 +121,7 @@ ...@@ -121,7 +121,7 @@
}, },
submitForm: function () { submitForm: function () {
var $form = this, var $form = $(this),
data = $form.data('yiiActiveForm'); data = $form.data('yiiActiveForm');
if (data.validated) { if (data.validated) {
// continue submitting the form since validation passes // continue submitting the form since validation passes
...@@ -163,7 +163,7 @@ ...@@ -163,7 +163,7 @@
}, },
resetForm: function () { resetForm: function () {
var $form = this; var $form = $(this);
var data = $form.data('yiiActiveForm'); var data = $form.data('yiiActiveForm');
// Because we bind directly to a form reset event instead of a reset button (that may not exist), // Because we bind directly to a form reset event instead of a reset button (that may not exist),
// when this function is executed form input values have not been reset yet. // when this function is executed form input values have not been reset yet.
......
...@@ -95,9 +95,9 @@ class Html ...@@ -95,9 +95,9 @@ class Html
public static $attributeOrder = array( public static $attributeOrder = array(
'type', 'type',
'id', 'id',
'class',
'name', 'name',
'value', 'value',
'class',
'href', 'href',
'src', 'src',
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
namespace yii\web; namespace yii\web;
use Yii; use Yii;
use yii\helpers\Html;
/** /**
* Controller is the base class of Web controllers. * Controller is the base class of Web controllers.
......
...@@ -115,6 +115,7 @@ class Response extends \yii\base\Response ...@@ -115,6 +115,7 @@ class Response extends \yii\base\Response
* <li>forceDownload: specifies whether the file will be downloaded or shown inline, defaults to true</li> * <li>forceDownload: specifies whether the file will be downloaded or shown inline, defaults to true</li>
* <li>addHeaders: an array of additional http headers in header-value pairs</li> * <li>addHeaders: an array of additional http headers in header-value pairs</li>
* </ul> * </ul>
* @todo
*/ */
public function xSendFile($filePath, $options = array()) public function xSendFile($filePath, $options = array())
{ {
...@@ -196,6 +197,19 @@ class Response extends \yii\base\Response ...@@ -196,6 +197,19 @@ class Response extends \yii\base\Response
} }
/** /**
* Refreshes the current page.
* The effect of this method call is the same as the user pressing the refresh button of his browser
* (without re-posting data).
* @param boolean $terminate whether to terminate the current application after calling this method
* @param string $anchor the anchor that should be appended to the redirection URL.
* Defaults to empty. Make sure the anchor starts with '#' if you want to specify it.
*/
public function refresh($terminate = true, $anchor = '')
{
$this->redirect(Yii::$app->getRequest()->getUrl() . $anchor, $terminate);
}
/**
* Returns the cookie collection. * Returns the cookie collection.
* Through the returned cookie collection, you add or remove cookies as follows, * Through the returned cookie collection, you add or remove cookies as follows,
* *
......
...@@ -48,13 +48,18 @@ class ActiveField extends Component ...@@ -48,13 +48,18 @@ class ActiveField extends Component
*/ */
public $template = "{label}\n<div class=\"controls\">\n{input}\n{error}\n</div>"; public $template = "{label}\n<div class=\"controls\">\n{input}\n{error}\n</div>";
/** /**
* @var array the default options for the error message. This property is used when calling [[error()]] * @var array the default options for the input tags. The parameter passed to individual input methods
* without the `$options` parameter. * (e.g. [[textInput()]]) will be merged with this property when rendering the input tag.
*/
public $inputOptions = array();
/**
* @var array the default options for the error tags. The parameter passed to [[error()]] will be
* merged with this property when rendering the error tag.
*/ */
public $errorOptions = array('tag' => 'span', 'class' => 'help-inline'); public $errorOptions = array('tag' => 'span', 'class' => 'help-inline');
/** /**
* @var array the default options for the label. This property is used when calling [[label()]] * @var array the default options for the label tags. The parameter passed to [[label()]] will be
* without the `$options` parameter. * merged with this property when rendering the label tag.
*/ */
public $labelOptions = array('class' => 'control-label'); public $labelOptions = array('class' => 'control-label');
/** /**
...@@ -174,7 +179,7 @@ class ActiveField extends Component ...@@ -174,7 +179,7 @@ class ActiveField extends Component
/** /**
* Generates a label tag for [[attribute]]. * Generates a label tag for [[attribute]].
* The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]]. * The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]].
* @param array $options the tag options in terms of name-value pairs. If this is null, [[labelOptions]] will be used. * @param array $options the tag options in terms of name-value pairs. It will be merged with [[labelOptions]].
* The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded * The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded
* using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. * using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
* *
...@@ -186,18 +191,16 @@ class ActiveField extends Component ...@@ -186,18 +191,16 @@ class ActiveField extends Component
* *
* @return string the generated label tag * @return string the generated label tag
*/ */
public function label($options = null) public function label($options = array())
{ {
if ($options === null) { $options = array_merge($this->labelOptions, $options);
$options = $this->labelOptions;
}
return Html::activeLabel($this->model, $this->attribute, $options); return Html::activeLabel($this->model, $this->attribute, $options);
} }
/** /**
* Generates a tag that contains the first validation error of [[attribute]]. * Generates a tag that contains the first validation error of [[attribute]].
* Note that even if there is no validation error, this method will still return an empty error tag. * Note that even if there is no validation error, this method will still return an empty error tag.
* @param array $options the tag options in terms of name-value pairs. If this is null, [[errorOptions]] will be used. * @param array $options the tag options in terms of name-value pairs. It will be merged with [[errorOptions]].
* The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded * The options will be rendered as the attributes of the resulting tag. The values will be HTML-encoded
* using [[encode()]]. If a value is null, the corresponding attribute will not be rendered. * using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
* *
...@@ -207,11 +210,9 @@ class ActiveField extends Component ...@@ -207,11 +210,9 @@ class ActiveField extends Component
* *
* @return string the generated label tag * @return string the generated label tag
*/ */
public function error($options = null) public function error($options = array())
{ {
if ($options === null) { $options = array_merge($this->errorOptions, $options);
$options = $this->errorOptions;
}
$attribute = Html::getAttributeName($this->attribute); $attribute = Html::getAttributeName($this->attribute);
$error = $this->model->getFirstError($attribute); $error = $this->model->getFirstError($attribute);
$tag = isset($options['tag']) ? $options['tag'] : 'span'; $tag = isset($options['tag']) ? $options['tag'] : 'span';
...@@ -244,6 +245,7 @@ class ActiveField extends Component ...@@ -244,6 +245,7 @@ class ActiveField extends Component
*/ */
public function input($type, $options = array()) public function input($type, $options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeInput($type, $this->model, $this->attribute, $options)); return $this->render(Html::activeInput($type, $this->model, $this->attribute, $options));
} }
...@@ -257,6 +259,7 @@ class ActiveField extends Component ...@@ -257,6 +259,7 @@ class ActiveField extends Component
*/ */
public function textInput($options = array()) public function textInput($options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeTextInput($this->model, $this->attribute, $options)); return $this->render(Html::activeTextInput($this->model, $this->attribute, $options));
} }
...@@ -270,6 +273,7 @@ class ActiveField extends Component ...@@ -270,6 +273,7 @@ class ActiveField extends Component
*/ */
public function hiddenInput($options = array()) public function hiddenInput($options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeHiddenInput($this->model, $this->attribute, $options)); return $this->render(Html::activeHiddenInput($this->model, $this->attribute, $options));
} }
...@@ -283,6 +287,7 @@ class ActiveField extends Component ...@@ -283,6 +287,7 @@ class ActiveField extends Component
*/ */
public function passwordInput($options = array()) public function passwordInput($options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activePasswordInput($this->model, $this->attribute, $options)); return $this->render(Html::activePasswordInput($this->model, $this->attribute, $options));
} }
...@@ -296,6 +301,7 @@ class ActiveField extends Component ...@@ -296,6 +301,7 @@ class ActiveField extends Component
*/ */
public function fileInput($options = array()) public function fileInput($options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeFileInput($this->model, $this->attribute, $options)); return $this->render(Html::activeFileInput($this->model, $this->attribute, $options));
} }
...@@ -308,6 +314,7 @@ class ActiveField extends Component ...@@ -308,6 +314,7 @@ class ActiveField extends Component
*/ */
public function textarea($options = array()) public function textarea($options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeTextarea($this->model, $this->attribute, $options)); return $this->render(Html::activeTextarea($this->model, $this->attribute, $options));
} }
...@@ -331,6 +338,7 @@ class ActiveField extends Component ...@@ -331,6 +338,7 @@ class ActiveField extends Component
*/ */
public function radio($options = array(), $enclosedByLabel = true) public function radio($options = array(), $enclosedByLabel = true)
{ {
$options = array_merge($this->inputOptions, $options);
if ($enclosedByLabel) { if ($enclosedByLabel) {
$hidden = ''; $hidden = '';
$radio = Html::activeRadio($this->model, $this->attribute, $options); $radio = Html::activeRadio($this->model, $this->attribute, $options);
...@@ -369,6 +377,7 @@ class ActiveField extends Component ...@@ -369,6 +377,7 @@ class ActiveField extends Component
*/ */
public function checkbox($options = array(), $enclosedByLabel = true) public function checkbox($options = array(), $enclosedByLabel = true)
{ {
$options = array_merge($this->inputOptions, $options);
if ($enclosedByLabel) { if ($enclosedByLabel) {
$hidden = ''; $hidden = '';
$checkbox = Html::activeCheckbox($this->model, $this->attribute, $options); $checkbox = Html::activeCheckbox($this->model, $this->attribute, $options);
...@@ -421,6 +430,7 @@ class ActiveField extends Component ...@@ -421,6 +430,7 @@ class ActiveField extends Component
*/ */
public function dropDownList($items, $options = array()) public function dropDownList($items, $options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeDropDownList($this->model, $this->attribute, $items, $options)); return $this->render(Html::activeDropDownList($this->model, $this->attribute, $items, $options));
} }
...@@ -461,6 +471,7 @@ class ActiveField extends Component ...@@ -461,6 +471,7 @@ class ActiveField extends Component
*/ */
public function listBox($items, $options = array()) public function listBox($items, $options = array())
{ {
$options = array_merge($this->inputOptions, $options);
return $this->render(Html::activeListBox($this->model, $this->attribute, $items, $options)); return $this->render(Html::activeListBox($this->model, $this->attribute, $items, $options));
} }
......
...@@ -40,9 +40,7 @@ class ActiveForm extends Widget ...@@ -40,9 +40,7 @@ class ActiveForm extends Widget
/** /**
* @var array the default configuration used by [[field()]] when creating a new field object. * @var array the default configuration used by [[field()]] when creating a new field object.
*/ */
public $fieldConfig = array( public $fieldConfig;
'class' => 'yii\widgets\ActiveField',
);
/** /**
* @var string the default CSS class for the error summary container. * @var string the default CSS class for the error summary container.
* @see errorSummary() * @see errorSummary()
...@@ -121,6 +119,9 @@ class ActiveForm extends Widget ...@@ -121,6 +119,9 @@ class ActiveForm extends Widget
if (!isset($this->options['id'])) { if (!isset($this->options['id'])) {
$this->options['id'] = $this->getId(); $this->options['id'] = $this->getId();
} }
if (!isset($this->fieldConfig['class'])) {
$this->fieldConfig['class'] = 'yii\widgets\ActiveField';
}
echo Html::beginForm($this->action, $this->method, $this->options); echo Html::beginForm($this->action, $this->method, $this->options);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment