溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何實(shí)現(xiàn)一個(gè)symfony表單

發(fā)布時(shí)間:2021-02-03 12:39:35 來(lái)源:億速云 閱讀:133 作者:Leah 欄目:開發(fā)技術(shù)

這篇文章給大家介紹如何實(shí)現(xiàn)一個(gè)symfony表單,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

具體如下:

symfony開發(fā)很簡(jiǎn)潔,但是功能的數(shù)量仍然很缺乏?,F(xiàn)在是時(shí)候進(jìn)行一些askeet站點(diǎn)與用戶之間的交互了。而HTML交互的根本--除了起鏈接--就是表單了。

這里我們的目標(biāo)是允許用戶登陸,并在主頁(yè)的問(wèn)題列表中進(jìn)行翻閱。這對(duì)于開發(fā)而言是很快的,并且可以讓我們回憶起前面的內(nèi)容。

登陸表單

在測(cè)試數(shù)據(jù)中存在用戶,但是程序卻沒有辦法來(lái)進(jìn)行驗(yàn)證。下面我們要在程序的每一個(gè)頁(yè)面添加一個(gè)登陸表單。打開全局的布局文件askeet/apps/frontend/templates/layout.php,并且在到about的連接之前添加下面的代碼行:

復(fù)制代碼 代碼如下:

<li><?php echo link_to('sign in', 'user/login') ?></li>

當(dāng)前的布局將這些鏈接放在web調(diào)試工具欄之后。要看到這些鏈接,點(diǎn)擊'Sf'圖標(biāo)折疊起調(diào)試工具欄就可以看到了。

現(xiàn)在需要?jiǎng)?chuàng)建user模塊。而question模塊是在第二天生成的,這一次我們只是叫symfony來(lái)創(chuàng)建模塊框架,而我們將會(huì)自己來(lái)編寫這些代碼。

復(fù)制代碼 代碼如下:

$ symfony init-module frontend user

這個(gè)框架包含一個(gè)默認(rèn)的index動(dòng)作與一個(gè)indexSuccess.php模板。刪除他們,因?yàn)槲覀儾⒉恍枰麄儭?/p>

創(chuàng)建user/login動(dòng)作

復(fù)制代碼 代碼如下:

在user/actions/action.class.php文件中,添加下面的登陸動(dòng)作:

public function executeLogin()
{
  $this->getRequest()->setAttribute('referer', $this->getRequest()->getReferer());
 
  return sfView::SUCCESS;
}

這個(gè)動(dòng)作將referer保存在請(qǐng)求屬性中。然后這個(gè)屬性可為模塊所用存放在一個(gè)隱藏區(qū)域中,從而這個(gè)表單的目的動(dòng)作可以在成功登陸后重定向到原始的referer。

語(yǔ)句return sfView::SUCCESS將動(dòng)作執(zhí)行結(jié)果傳遞到loginSuccess.php模塊。這條語(yǔ)句是在一個(gè)不包含返回語(yǔ)句的動(dòng)作中實(shí)現(xiàn)的,這也就是一個(gè)動(dòng)作的默認(rèn)模塊被稱之為actionnameSuccess.php的原因。

在動(dòng)作上開始更多的工作之前,我們先來(lái)看一下模塊。

創(chuàng)建loginSuccess.php模塊

web上的許多人機(jī)交互使用表單,而Symfony通過(guò)提供一個(gè)form幫助器集合來(lái)組織表單的創(chuàng)建與管理。

在askeet/apps/frontend/modules/user/templates/目錄下,創(chuàng)建下面的loginSuccess.php模塊:

復(fù)制代碼 代碼如下:

<?php echo form_tag('user/login') ?>
 
  <fieldset>
 
  <div class="form-row">
    <label for="nickname">nickname:</label>
    <?php echo input_tag('nickname', $sf_params->get('nickname')) ?>
  </div>
 
  <div class="form-row">
    <label for="password">password:</label>
    <?php echo input_password_tag('password') ?>
  </div>
 
  </fieldset>
 
  <?php echo input_hidden_tag('referer', $sf_request->getAttribute('referer')) ?>
  <?php echo submit_tag('sign in') ?>
 
</form>

這個(gè)模塊是我們第一次使用表單幫助器。這些Symfony函數(shù)可以幫助我們自動(dòng)化編寫表單標(biāo)簽。form_tag()打開一從此標(biāo)簽,使用POST作為默認(rèn)的動(dòng)作,并且指向作為參數(shù)傳遞的動(dòng)作。input_tag()幫助器產(chǎn)生一個(gè)<input>標(biāo)簽,并且依據(jù)所傳遞的第一個(gè)參數(shù)自動(dòng)添加一個(gè)id屬性;而默認(rèn)值則是由第二個(gè)參數(shù)得到。我們可以在Symfony一書的相關(guān)章節(jié)查找到更多的關(guān)于表單幫助器與他們所產(chǎn)生的HTML代碼的內(nèi)容。

這里的實(shí)質(zhì)是當(dāng)表單提交時(shí)則會(huì)調(diào)用這個(gè)動(dòng)作。所以我們返回來(lái)看一下這個(gè)動(dòng)作。

處理表單提交

用下面的代碼來(lái)替換我們剛才所編寫的登陸動(dòng)作:

復(fù)制代碼 代碼如下:

public function executeLogin()
{
  if ($this->getRequest()->getMethod() != sfRequest::POST)
  {
    // display the form
    $this->getRequest()->setAttribute('referer', $this->getRequest()->getReferer());
  }
  else
  {
    // handle the form submission
    $nickname = $this->getRequestParameter('nickname');
 
    $c = new Criteria();
    $c->add(UserPeer::NICKNAME, $nickname);
    $user = UserPeer::doSelectOne($c);
 
    // nickname exists?
    if ($user)
    {
      // password is OK?
      if (true)
      {
        $this->getUser()->setAuthenticated(true);
        $this->getUser()->addCredential('subscriber');
 
        $this->getUser()->setAttribute('subscriber_id', $user->getId(), 'subscriber');
        $this->getUser()->setAttribute('nickname', $user->getNickname(), 'subscriber');
 
        // redirect to last page
        return $this->redirect($this->getRequestParameter('referer', '@homepage'));
      }
    }
  }
}

登陸動(dòng)作可以同時(shí)用來(lái)顯示登陸表單并且進(jìn)行處理。相應(yīng)的,他必須知道所調(diào)用的環(huán)境。如果這個(gè)動(dòng)作并沒有在POST模式下調(diào)用(因?yàn)槭怯梢粋€(gè)鏈接來(lái)請(qǐng)求的):而這正是我們?cè)谇懊嫠懻摰那闆r。如果是在POST模式下請(qǐng)求的,那么則會(huì)由表單調(diào)用這個(gè)動(dòng)作并進(jìn)行相應(yīng)的處理。

這個(gè)動(dòng)作會(huì)由請(qǐng)求參數(shù)得到nickname域的值,并且查詢User表來(lái)查看在數(shù)據(jù)庫(kù)是否存在此用戶。

將來(lái)一個(gè)密碼控制將會(huì)為用戶分配憑證。但是現(xiàn)在,這個(gè)動(dòng)作所做的只是在一個(gè)會(huì)話屬性中存儲(chǔ)用戶的id與nickname屬性。最后,這個(gè)動(dòng)作重定向到表單中隱藏中的原始referer域,這是作為一個(gè)請(qǐng)求參數(shù)傳遞的。如果這個(gè)域是空的,則會(huì)使用默認(rèn)值。

這里我們需要注意這個(gè)例子中兩種類型的屬性集合之間的區(qū)別:request attributes($this->getRequest()->setAttribute())是為模板所保存的,而且只要答案發(fā)送到referer則會(huì)被忘記。session attributes($this->getUser()->setAttribute())是在整個(gè)用戶會(huì)話生命期被保存的,而且在將來(lái)其他的動(dòng)作也可以訪問(wèn)他們。如果我們希望了解更多的關(guān)于屬性的內(nèi)容,我們可以查看Symfony一書的參數(shù)保存器一節(jié)。

分配權(quán)限

用戶可以登陸進(jìn)askeet網(wǎng)站是一件好事,但是用戶并不僅是因?yàn)楹猛娑顷?。發(fā)表一個(gè)新問(wèn)題,對(duì)某一個(gè)問(wèn)題表示興趣,評(píng)價(jià)一個(gè)評(píng)論都需要登陸。而其他的動(dòng)作將會(huì)向非登陸用戶開放。

要將一個(gè)用戶設(shè)置為經(jīng)過(guò)驗(yàn)證的,我們需要調(diào)用sfUser對(duì)象的->setAuthenticated()方法。這個(gè)對(duì)象同時(shí)提供了一個(gè)證書機(jī)制(->addCredential()),來(lái)通過(guò)配置限制訪問(wèn)。Symfony一書的用戶證書一節(jié)對(duì)此進(jìn)行了詳細(xì)的解釋。

這就是下面兩行的目的:

復(fù)制代碼 代碼如下:

$this->getContext()->getUser()->setAuthenticated(true);
$this->getContext()->getUser()->addCredential('subscriber');

當(dāng)nickname被識(shí)別后,不僅用戶數(shù)據(jù)被存放在會(huì)話屬性中,而且這個(gè)用戶也會(huì)被分配網(wǎng)站限制部分的訪問(wèn)權(quán)限。在明天我們將會(huì)看到如何限制驗(yàn)證用戶的程序訪問(wèn)。

添加user/logout動(dòng)作

關(guān)于->setAttribute()方法還有最后一個(gè)竅門:最后一個(gè)參數(shù)(上面例子中的subscriber)定義了屬性存放的名字空間。一個(gè)名字空間不僅允許一個(gè)在另一個(gè)名字空間存在的名字指定給一個(gè)屬性,而且可以使用一個(gè)命令快速移除所有這些屬性:

復(fù)制代碼 代碼如下:

public function executeLogout()
{
  $this->getUser()->setAuthenticated(false);
  $this->getUser()->clearCredentials();
 
  $this->getUser()->getAttributeHolder()->removeNamespace('subscriber');
 
  $this->redirect('@homepage');
}

使用名字空間可以省去我們一個(gè)一個(gè)移除這些屬性的麻煩:這只是一行語(yǔ)句。

更新布局

當(dāng)前這個(gè)布局即使用戶已經(jīng)登陸仍然顯示一個(gè)'login'鏈接。讓我們來(lái)修正這一點(diǎn)。在askeet/apps/frontend/templates/layout.php文件中,修改我們?cè)诮裉斓闹改祥_始時(shí)所修改的代碼:

復(fù)制代碼 代碼如下:

<?php if ($sf_user->isAuthenticated()): ?>
  <li><?php echo link_to('sign out', 'user/logout') ?></li>
  <li><?php echo link_to($sf_user->getAttribute('nickname', '', 'subscriber').' profile', 'user/profile') ?></li>
<?php else: ?>
  <li><?php echo link_to('sign in/register', 'user/login') ?></li>
<?php endif ?>

現(xiàn)在是時(shí)候進(jìn)行測(cè)試了,我們可以顯示程序的任何一頁(yè),點(diǎn)擊'login'鏈接,輸入一個(gè)可用的昵稱('anonymous'為例)并且進(jìn)行驗(yàn)證。如果窗口頂部的'login'變?yōu)?#39;sign out',則我們所做的一切都是正確的。最后,試著注銷來(lái)查看'login'鏈接是否再次出現(xiàn)。

問(wèn)題組織

隨著數(shù)以千計(jì)的Symfony愛好者訪問(wèn)askeet網(wǎng)站,在主頁(yè)上顯示的問(wèn)題就會(huì)逐漸變多。為了避免變慢的請(qǐng)求速度,問(wèn)題列的隨意翻閱就成為必須解決的問(wèn)題。

Symfony為這一目的提供了一個(gè)對(duì)象:sfPropelPager。他會(huì)封裝到數(shù)據(jù)的請(qǐng)求,從而只會(huì)查詢當(dāng)前頁(yè)面所顯示的記錄。例如,如果一個(gè)頁(yè)面初始化時(shí)每頁(yè)只顯示10個(gè)問(wèn)題,則到數(shù)據(jù)的請(qǐng)求只會(huì)限制為10個(gè)結(jié)果,并且會(huì)設(shè)置偏移來(lái)在頁(yè)面中進(jìn)行匹配。

修改question/list動(dòng)作

在前面的練習(xí)中,我們看到了問(wèn)題模塊的顯示動(dòng)作:

復(fù)制代碼 代碼如下:

public function executeList ()
{
  $this->questions = QuestionPeer::doSelect(new Criteria());
}

我們將會(huì)修改這個(gè)動(dòng)作來(lái)向模板傳遞一個(gè)sfPropelPager而不是傳遞一個(gè)數(shù)組。同時(shí),我們會(huì)依據(jù)感興趣的數(shù)量來(lái)對(duì)問(wèn)題進(jìn)行排序:

復(fù)制代碼 代碼如下:

public function executeList ()
{
  $pager = new sfPropelPager('Question', 2);
  $c = new Criteria();
  $c->addDescendingOrderByColumn(QuestionPeer::INTERESTED_USERS);
  $pager->setCriteria($c);
  $pager->setPage($this->getRequestParameter('page', 1));
  $pager->setPeerMethod('doSelectJoinUser');
  $pager->init();
 
  $this->question_pager = $pager;
}

sfPropelPager對(duì)象的初始化指明了他包含哪個(gè)對(duì)象類,以及在一個(gè)頁(yè)面中可以放置的對(duì)象的最大數(shù)目(在這個(gè)例子中為2)。->setPage()方法使用一個(gè)請(qǐng)求參數(shù)來(lái)設(shè)置當(dāng)前頁(yè)面。例如,如果這個(gè)頁(yè)面參數(shù)的值為2,sfPropelPager將會(huì)返回3到5的結(jié)果。頁(yè)面請(qǐng)求參數(shù)的值變?yōu)?,則頁(yè)面默認(rèn)會(huì)返回1到2的結(jié)果。我們可以在Symfony一書的頁(yè)面章節(jié)中了解到關(guān)于sfPropelPager對(duì)象及其方法的更多信息。

使用一個(gè)默認(rèn)參數(shù)

將常量放在我們所使用的配置文件中是一個(gè)好主意。例如,每頁(yè)的結(jié)果(在這個(gè)例子為2)可以由一個(gè)在我們自定義的程序配置中的參數(shù)來(lái)代替。用下面的代碼來(lái)改變上面的sfPropelPager行:

復(fù)制代碼 代碼如下:

..
  $pager = new sfPropelPager('Question', sfConfig::get('app_pager_homepage_max'));

這里的pager關(guān)鍵字是作為名字空間使用的,這也就是為什么在參數(shù)名字中出現(xiàn)的原因。我們可以在Symfony一書的配置一節(jié)中查看到更多的關(guān)于自定義配置與命名自定義參數(shù)規(guī)則的更多的內(nèi)容。

修改listSuccess.php模板

在listSuccess.php模板中,將下面的代碼行:

復(fù)制代碼 代碼如下:

<?php foreach($questions as $question): ?>

替換為

復(fù)制代碼 代碼如下:

<?php foreach($question_pager->getResults() as $question): ?>

從而頁(yè)面顯示存儲(chǔ)在頁(yè)面中的結(jié)果列表。

添加頁(yè)面瀏覽

在這個(gè)模板中還需要做另外一件事:頁(yè)面瀏覽?,F(xiàn)在,模板所做的只是顯示前兩個(gè)問(wèn)題,但是我們應(yīng)添加到下一個(gè)頁(yè)面的功能,以及回到前一個(gè)頁(yè)面的功能。要完成添加這些功能,我們需要在模板后面添加下面的代碼:

復(fù)制代碼 代碼如下:

<div id="question_pager">
<?php if ($question_pager->haveToPaginate()): ?>
  <?php echo link_to('&laquo;', 'question/list?page=1') ?>
  <?php echo link_to('&lt;', 'question/list?page='.$question_pager->getPreviousPage()) ?>
 
  <?php foreach ($question_pager->getLinks() as $page): ?>
    <?php echo link_to_unless($page == $question_pager->getPage(), $page, 'question/list?page='.$page) ?>
    <?php echo ($page != $question_pager->getCurrentMaxLink()) ? '-' : '' ?>
  <?php endforeach; ?>
 
  <?php echo link_to('&gt;', 'question/list?page='.$question_pager->getNextPage()) ?>
  <?php echo link_to('&raquo;', 'question/list?page='.$question_pager->getLastPage()) ?>
<?php endif; ?>
</div>

這段代碼利用了sfPropelPager對(duì)象的各種方法,以及->haveToPaginate(),這個(gè)函數(shù)只有在請(qǐng)求的結(jié)果數(shù)目超過(guò)了頁(yè)面尺寸時(shí)才會(huì)返回真;而->getPreviousPage(),->getNextPage(),->getLastPage()都具有明顯示的意義;->getLinks()函數(shù)提供了一個(gè)頁(yè)面號(hào)的數(shù)組;而->getCurrentMaxLink()函數(shù)返回最后的頁(yè)面號(hào)。

這個(gè)例子同時(shí)顯示了一個(gè)Symfony鏈接幫助器:link_to_unless()會(huì)在作為第一個(gè)參數(shù)的測(cè)試為假的情況下輸出一個(gè)常規(guī)link_to(),否則會(huì)輸出一個(gè)非鏈接的文本,并使用簡(jiǎn)單的<span>包裝。

我們測(cè)試這個(gè)頁(yè)面了嗎?我們應(yīng)進(jìn)行測(cè)試。直到我們用我們自己的眼睛來(lái)驗(yàn)證,這個(gè)修改才算結(jié)束。要進(jìn)行測(cè)試,打開在第三天所創(chuàng)建的測(cè)試數(shù)據(jù)文件,并且為要顯示的頁(yè)面瀏覽添加一些問(wèn)題。重新運(yùn)行導(dǎo)入數(shù)據(jù)批處理文件,然后再一次請(qǐng)求主頁(yè)。

為子頁(yè)添加路由規(guī)則

默認(rèn)情況下,頁(yè)面規(guī)則如下:

http://askeet/frontend_dev.php/question/list/page/XX

現(xiàn)在我們利用路由規(guī)則使用這些頁(yè)面更易于理解:

http://askeet/frontend_dev.php/index/XX

打開apps/frontend/config/routing.yml文件并且在頂部添加下面內(nèi)容:

復(fù)制代碼 代碼如下:

popular_questions:
  url:   /index/:page
  param: { module: question, action: list }

并且為登陸頁(yè)面添加另外的路由規(guī)則:

復(fù)制代碼 代碼如下:

login:
  url:   /login
  param: { module: user, action: login }

重構(gòu)

模型

question/list動(dòng)作執(zhí)行與模型相關(guān)的代碼,這也就是我們?yōu)槭裁匆獙⑦@些代碼移動(dòng)到模塊中的原因。用下面的代碼來(lái)代替question/list動(dòng)作:

復(fù)制代碼 代碼如下:

public function executeList ()
{
  $this->question_pager = QuestionPeer::getHomepagePager($this->getRequestParameter('page', 1));
}

并且在lib/model中的QuestionPeer.php類中添加下面的方法:

復(fù)制代碼 代碼如下:

public static function getHomepagePager($page)
{
  $pager = new sfPropelPager('Question', sfConfig::get('app_pager_homepage_max'));
  $c = new Criteria();
  $c->addDescendingOrderByColumn(self::INTERESTED_USERS);
  $pager->setCriteria($c);
  $pager->setPage($page);
  $pager->setPeerMethod('doSelectJoinUser');
  $pager->init();
 
  return $pager;
}

同樣的想法也適用于我們昨天編寫的question/show動(dòng)作:Propel對(duì)象由其剝離的標(biāo)題取回問(wèn)題的用法應(yīng)屬于這個(gè)模塊。所以用下面的代碼來(lái)變更question/show動(dòng)作代碼:

復(fù)制代碼 代碼如下:

public function executeShow()
{
  $this->question = QuestionPeer::getQuestionFromTitle($this->getRequestParameter('stripped_title'));
 
  $this->forward404Unless($this->question);
}

在QuestionPeer.php文件中添加下面的代碼:

復(fù)制代碼 代碼如下:

public static function getQuestionFromTitle($title)
{
  $c = new Criteria();
  $c->add(QuestionPeer::STRIPPED_TITLE, $title);
 
  return self::doSelectOne($c);
}

模板

在question/templates/listSuccess.php中顯示的問(wèn)題列表在將來(lái)的某些地方還會(huì)用到。所以我們將顯示問(wèn)題列表的模板代碼放在一個(gè)_list.php片段中,并且用下面的簡(jiǎn)單代碼來(lái)代替listSuccess.php的內(nèi)容:

復(fù)制代碼 代碼如下:

<h2>popular question</h2>

<?php echo include_partial('list',array('question_pager'=>$question_pager)) ?>

關(guān)于如何實(shí)現(xiàn)一個(gè)symfony表單就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI