./bin/agavi action-wizard
# Module: Default
# Action: Contact
# Views: Input Error Success
產生:`ContactAction`、`ContactInputView`、`ContactErrorView`、`ContactSuccessView` + 對應模板。
<route name="contact" pattern="^/contact$" module="Default" action="Contact" />
<?php
// app/modules/Default/actions/ContactAction.class.php
class Default_ContactAction extends AgaviAction
{
public function execute(AgaviRequestDataHolder $rd)
{
// 1. 表單已送出 (POST)
if ($rd->getParameter('submit')) {
// 驗證在 validate() 自動執行,若通過這裡即為合法資料
$data = [
'name' => $rd->getParameter('name'),
'email' => $rd->getParameter('email'),
'subject' => $rd->getParameter('subject'),
'message' => $rd->getParameter('message'),
];
// 2. 業務邏輯:發送郵件、寫入資料庫等
$this->getContext()->getMailer()->sendContactMail($data);
// 3. 設定成功訊息
$this->setAttribute('data', $data);
return 'Success';
}
// 3. 首次 GET 請求 → 顯示空白表單
return 'Input';
}
public function validate(AgaviValidator $validator)
{
// 必填
$validator->addRule('name', new AgaviRequiredValidator());
$validator->addRule('email', new AgaviRequiredValidator());
$validator->addRule('subject', new AgaviRequiredValidator());
$validator->addRule('message', new AgaviRequiredValidator());
// 格式
$validator->addRule('email', new AgaviEmailValidator());
$validator->addRule('name', new AgaviStringValidator(['max_length' => 100]));
$validator->addRule('subject', new AgaviStringValidator(['max_length' => 150]));
$validator->addRule('message', new AgaviStringValidator(['min_length' => 10, 'max_length' => 5000]));
// CSRF 保護 (需在表單加入 csrfToken() ?>)
$validator->addRule('csrf_token', new AgaviCsrfValidator());
}
// 可選:驗證失敗時自訂錯誤處理
public function handleError($errors)
{
// 將錯誤傳給 Error View
$this->setAttribute('errors', $errors);
return 'Error';
}
}
<?php
// app/modules/Default/views/ContactInputView.class.php
class Default_ContactInputView extends AgaviHtmlView
{
public function setupHtml()
{
$this->setLayout('Master');
}
}
<?php // app/modules/Default/templates/ContactInput.php ?>
<h1>聯絡我們</h1>
<?php if ($t->hasAttribute('errors')): ?>
<div class="alert alert-danger">
<ul>
<?php foreach ($t->getAttribute('errors') as $field => $msgs): ?>
<?php foreach ($msgs as $msg): ?>
<li><strong><?= ucfirst($field) ?>:</strong> <?= $msg ?></li>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<form method="POST" action="<?= $ro->gen('contact') ?>">
<input type="hidden" name="csrf_token" value="<?= $ro->csrfToken() ?>">
<div class="form-group">
<label>姓名</label>
<input type="text" name="name" value="<?= $t->getAttribute('name', '') ?>" class="form-control" required>
</div>
<div class="form-group">
<label>Email</label>
<input type="email" name="email" value="<?= $t->getAttribute('email', '') ?>" class="form-control" required>
</div>
<div class="form-group">
<label>主旨</label>
<input type="text" name="subject" value="<?= $t->getAttribute('subject', '') ?>" class="form-control" required>
</div>
<div class="form-group">
<label>內容</label>
<textarea name="message" class="form-control" rows="6" required><?= $t->getAttribute('message', '') ?></textarea>
</div>
<button type="submit" name="submit" value="1" class="btn btn-primary">送出</button>
</form>
<?php // app/modules/Default/templates/ContactSuccess.php ?>
<div class="alert alert-success">
<h2>感謝您的來信!</h2>
<p>我們已收到您的訊息,將盡快回覆。</p>
<dl class="dl-horizontal">
<dt>姓名</dt><dd><?= $t->getAttribute('data.name') ?></dd>
<dt>Email</dt><dd><?= $t->getAttribute('data.email') ?></dd>
<dt>主旨</dt><dd><?= $t->getAttribute('data.subject') ?></dd>
</dl>
<p><a href="<?= $ro->gen('default.index') ?>" class="btn btn-link">返回首頁</a></p>
</div>
| 概念 | 說明 |
|---|---|
| Input View | 專門處理 **GET 請求顯示空白/預填表單**,驗證失敗時也會導向此 View (透過 `handleError`)。 |
| Error View | 若 `handleError` 返回 `'Error'`,則渲染 `ContactErrorView`,適合 API 回傳 JSON 錯誤。 |
| 驗證器鏈 | `addRule` 可同一欄位疊加多個驗證器,依序執行,任一失敗即停止並收集錯誤訊息。 |
| CSRF Token | `$ro->csrfToken()` 產生並存入 Session,`AgaviCsrfValidator` 自動比對,防止跨站請求偽造。 |
| 資料回填 | `$t->getAttribute('field', '')` 安全輸出用戶輸入,避免 XSS。 |