亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > PHP > 正文

symfony表單與頁面實現技巧

2024-05-04 23:30:38
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了symfony表單與頁面實現技巧,實例分析了symfony表單與頁面的實現方法與相關注意事項,需要的朋友可以參考下
 

本文實例講述了symfony表單與頁面實現技巧。分享給大家供大家參考。具體如下:

symfony開發很簡潔,但是功能的數量仍然很缺乏。現在是時候進行一些askeet站點與用戶之間的交互了。而HTML交互的根本--除了起鏈接--就是表單了。

這里我們的目標是允許用戶登陸,并在主頁的問題列表中進行翻閱。這對于開發而言是很快的,并且可以讓我們回憶起前面的內容。

登陸表單

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

復制代碼代碼如下:
<li><?php echo link_to('sign in', 'user/login') ?></li>

 

當前的布局將這些鏈接放在web調試工具欄之后。要看到這些鏈接,點擊'Sf'圖標折疊起調試工具欄就可以看到了。

現在需要創建user模塊。而question模塊是在第二天生成的,這一次我們只是叫symfony來創建模塊框架,而我們將會自己來編寫這些代碼。

復制代碼代碼如下:
$ symfony init-module frontend user

 

這個框架包含一個默認的index動作與一個indexSuccess.php模板。刪除他們,因為我們并不需要他們。

創建user/login動作

復制代碼代碼如下:
在user/actions/action.class.php文件中,添加下面的登陸動作:

 

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

 

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

語句return sfView::SUCCESS將動作執行結果傳遞到loginSuccess.php模塊。這條語句是在一個不包含返回語句的動作中實現的,這也就是一個動作的默認模塊被稱之為actionnameSuccess.php的原因。

在動作上開始更多的工作之前,我們先來看一下模塊。

創建loginSuccess.php模塊

web上的許多人機交互使用表單,而Symfony通過提供一個form幫助器集合來組織表單的創建與管理。

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

復制代碼代碼如下:
<?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>

 

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

這里的實質是當表單提交時則會調用這個動作。所以我們返回來看一下這個動作。

處理表單提交

用下面的代碼來替換我們剛才所編寫的登陸動作:

復制代碼代碼如下:
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'));
      }
    }
  }
}

 

登陸動作可以同時用來顯示登陸表單并且進行處理。相應的,他必須知道所調用的環境。如果這個動作并沒有在POST模式下調用(因為是由一個鏈接來請求的):而這正是我們在前面所討論的情況。如果是在POST模式下請求的,那么則會由表單調用這個動作并進行相應的處理。

這個動作會由請求參數得到nickname域的值,并且查詢User表來查看在數據庫是否存在此用戶。

將來一個密碼控制將會為用戶分配憑證。但是現在,這個動作所做的只是在一個會話屬性中存儲用戶的id與nickname屬性。最后,這個動作重定向到表單中隱藏中的原始referer域,這是作為一個請求參數傳遞的。如果這個域是空的,則會使用默認值。

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

分配權限

用戶可以登陸進askeet網站是一件好事,但是用戶并不僅是因為好玩而登陸。發表一個新問題,對某一個問題表示興趣,評價一個評論都需要登陸。而其他的動作將會向非登陸用戶開放。

要將一個用戶設置為經過驗證的,我們需要調用sfUser對象的->setAuthenticated()方法。這個對象同時提供了一個證書機制(->addCredential()),來通過配置限制訪問。Symfony一書的用戶證書一節對此進行了詳細的解釋。

這就是下面兩行的目的:

復制代碼代碼如下:
$this->getContext()->getUser()->setAuthenticated(true);
$this->getContext()->getUser()->addCredential('subscriber');

 

當nickname被識別后,不僅用戶數據被存放在會話屬性中,而且這個用戶也會被分配網站限制部分的訪問權限。在明天我們將會看到如何限制驗證用戶的程序訪問。

添加user/logout動作

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

復制代碼代碼如下:
public function executeLogout()
{
  $this->getUser()->setAuthenticated(false);
  $this->getUser()->clearCredentials();
 
  $this->getUser()->getAttributeHolder()->removeNamespace('subscriber');
 
  $this->redirect('@homepage');
}

 

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

更新布局

當前這個布局即使用戶已經登陸仍然顯示一個'login'鏈接。讓我們來修正這一點。在askeet/apps/frontend/templates/layout.php文件中,修改我們在今天的指南開始時所修改的代碼:

復制代碼代碼如下:
<?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 ?>

 

現在是時候進行測試了,我們可以顯示程序的任何一頁,點擊'login'鏈接,輸入一個可用的昵稱('anonymous'為例)并且進行驗證。如果窗口頂部的'login'變為'sign out',則我們所做的一切都是正確的。最后,試著注銷來查看'login'鏈接是否再次出現。

問題組織

隨著數以千計的Symfony愛好者訪問askeet網站,在主頁上顯示的問題就會逐漸變多。為了避免變慢的請求速度,問題列的隨意翻閱就成為必須解決的問題。

Symfony為這一目的提供了一個對象:sfPropelPager。他會封裝到數據的請求,從而只會查詢當前頁面所顯示的記錄。例如,如果一個頁面初始化時每頁只顯示10個問題,則到數據的請求只會限制為10個結果,并且會設置偏移來在頁面中進行匹配。

修改question/list動作

在前面的練習中,我們看到了問題模塊的顯示動作:

復制代碼代碼如下:
public function executeList ()
{
  $this->questions = QuestionPeer::doSelect(new Criteria());
}

 

我們將會修改這個動作來向模板傳遞一個sfPropelPager而不是傳遞一個數組。同時,我們會依據感興趣的數量來對問題進行排序:

復制代碼代碼如下:
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對象的初始化指明了他包含哪個對象類,以及在一個頁面中可以放置的對象的最大數目(在這個例子中為2)。->setPage()方法使用一個請求參數來設置當前頁面。例如,如果這個頁面參數的值為2,sfPropelPager將會返回3到5的結果。頁面請求參數的值變為1,則頁面默認會返回1到2的結果。我們可以在Symfony一書的頁面章節中了解到關于sfPropelPager對象及其方法的更多信息。

使用一個默認參數

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

復制代碼代碼如下:
..
  $pager = new sfPropelPager('Question', sfConfig::get('app_pager_homepage_max'));

 

這里的pager關鍵字是作為名字空間使用的,這也就是為什么在參數名字中出現的原因。我們可以在Symfony一書的配置一節中查看到更多的關于自定義配置與命名自定義參數規則的更多的內容。

修改listSuccess.php模板

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

復制代碼代碼如下:
<?php foreach($questions as $question): ?>

 

替換為

復制代碼代碼如下:
<?php foreach($question_pager->getResults() as $question): ?>

 

從而頁面顯示存儲在頁面中的結果列表。

添加頁面瀏覽

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

復制代碼代碼如下:
<div id="question_pager">
<?php if ($question_pager->haveToPaginate()): ?>
  <?php echo link_to('«', 'question/list?page=1') ?>
  <?php echo link_to('<', '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('>', 'question/list?page='.$question_pager->getNextPage()) ?>
  <?php echo link_to('»', 'question/list?page='.$question_pager->getLastPage()) ?>
<?php endif; ?>
</div>

 

這段代碼利用了sfPropelPager對象的各種方法,以及->haveToPaginate(),這個函數只有在請求的結果數目超過了頁面尺寸時才會返回真;而->getPreviousPage(),->getNextPage(),->getLastPage()都具有明顯示的意義;->getLinks()函數提供了一個頁面號的數組;而->getCurrentMaxLink()函數返回最后的頁面號。

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

我們測試這個頁面了嗎?我們應進行測試。直到我們用我們自己的眼睛來驗證,這個修改才算結束。要進行測試,打開在第三天所創建的測試數據文件,并且為要顯示的頁面瀏覽添加一些問題。重新運行導入數據批處理文件,然后再一次請求主頁。

為子頁添加路由規則

默認情況下,頁面規則如下:

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

現在我們利用路由規則使用這些頁面更易于理解:

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

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

復制代碼代碼如下:
popular_questions: 
  url:   /index/:page 
  param: { module: question, action: list }

 

并且為登陸頁面添加另外的路由規則:

復制代碼代碼如下:
login: 
  url:   /login 
  param: { module: user, action: login }

 

重構

模型

question/list動作執行與模型相關的代碼,這也就是我們為什么要將這些代碼移動到模塊中的原因。用下面的代碼來代替question/list動作:

復制代碼代碼如下:
public function executeList () 

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

 

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

復制代碼代碼如下:
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動作:Propel對象由其剝離的標題取回問題的用法應屬于這個模塊。所以用下面的代碼來變更question/show動作代碼:

復制代碼代碼如下:
public function executeShow()
{
  $this->question = QuestionPeer::getQuestionFromTitle($this->getRequestParameter('stripped_title'));
 
  $this->forward404Unless($this->question);
}

 

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

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

 

模板

在question/templates/listSuccess.php中顯示的問題列表在將來的某些地方還會用到。所以我們將顯示問題列表的模板代碼放在一個_list.php片段中,并且用下面的簡單代碼來代替listSuccess.php的內容:

復制代碼代碼如下:
<h1>popular question</h1>

 

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

 

希望本文所述對大家的symfony框架程序設計有所幫助。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美在线视频免费观看| 成人a在线观看| 亚洲高清免费观看高清完整版| 久久99国产精品自在自在app| 久久国产精品首页| 久久精品国产免费观看| 日本精品久久电影| 亚洲老司机av| 久久天堂av综合合色| 国产精品v日韩精品| 精品视频久久久久久久| 国产精品丝袜白浆摸在线| 国产亚洲欧美日韩美女| 中文字幕免费精品一区| 久久亚洲精品国产亚洲老地址| 亚洲网站在线看| 精品视频在线播放免| 久久97精品久久久久久久不卡| 日韩欧美精品免费在线| 韩曰欧美视频免费观看| 国内偷自视频区视频综合| 98视频在线噜噜噜国产| 91精品久久久久久久久久久| 久久精品色欧美aⅴ一区二区| 国色天香2019中文字幕在线观看| 日韩女在线观看| 亚洲精品电影网在线观看| 国产偷国产偷亚洲清高网站| 久久亚洲国产成人| 国产福利精品在线| 亚洲国产私拍精品国模在线观看| 久久手机免费视频| 这里只有视频精品| 日韩有码在线观看| 日产日韩在线亚洲欧美| 国产69精品久久久久久| 亚洲三级av在线| 91九色精品视频| 国产精品成人国产乱一区| 亚洲精品在线不卡| 亚洲字幕一区二区| 亚洲国产精品高清久久久| 欧美日韩另类视频| 亚洲视频欧洲视频| 日韩亚洲综合在线| 成人黄色大片在线免费观看| 亚洲精品视频网上网址在线观看| 北条麻妃99精品青青久久| 91日韩在线视频| 性色av一区二区三区红粉影视| 亚洲第一视频网站| 日韩中文在线视频| 国产精品视频久久久| 国产精品日日做人人爱| 97视频色精品| 日韩av免费在线观看| 国产在线视频2019最新视频| 国产精品91在线观看| 91色在线观看| 国产在线拍揄自揄视频不卡99| 91av视频在线观看| 国产成人精品免高潮费视频| 97精品欧美一区二区三区| 亚洲日本成人女熟在线观看| 亚洲精品视频免费| 欧美另类精品xxxx孕妇| 成人激情视频网| 热re99久久精品国产66热| 亚洲欧美激情视频| 色综合天天狠天天透天天伊人| 亚洲国产精品嫩草影院久久| 欧美天天综合色影久久精品| 色噜噜狠狠狠综合曰曰曰| 亚洲精品xxxx| 成人精品网站在线观看| 51久久精品夜色国产麻豆| 日韩最新中文字幕电影免费看| 一本色道久久88综合日韩精品| 国产性猛交xxxx免费看久久| 福利微拍一区二区| 中文字幕欧美日韩精品| 国产婷婷色综合av蜜臀av| 成人午夜黄色影院| 九九热99久久久国产盗摄| 久久久91精品国产一区不卡| 久久久久国色av免费观看性色| 91探花福利精品国产自产在线| 国产视频久久网| 黄色精品一区二区| 91久久久久久| 亚洲区一区二区| 亚洲欧美在线看| 日韩有码视频在线| 亚洲加勒比久久88色综合| 国产精品电影网站| 九九热在线精品视频| 亚洲在线一区二区| 欧美激情视频网| 久久久久亚洲精品成人网小说| 在线观看国产精品淫| 日本欧美国产在线| 欧美日韩国产中字| 日韩美女中文字幕| 久久久久久av| 海角国产乱辈乱精品视频| 欧美乱人伦中文字幕在线| 日韩精品中文字| 国产精品成人一区二区| 亚洲最大福利网站| 性日韩欧美在线视频| 在线播放亚洲激情| 久久久久久18| 日韩理论片久久| 91免费看片网站| 久久久久久久久久久国产| 久久精品视频网站| 91精品国产色综合久久不卡98口| 久久综合色88| 精品一区精品二区| 亚洲国产欧美一区二区三区同亚洲| 国产精品爱啪在线线免费观看| 久久久久久国产免费| 美女视频久久黄| 国产精品一区二区三区在线播放| 中文字幕亚洲情99在线| 亚洲国产日韩欧美综合久久| 琪琪亚洲精品午夜在线| 81精品国产乱码久久久久久| 亚洲精品视频二区| 这里只有精品久久| 国产成人在线一区二区| 国产亚洲美女久久| 国产性猛交xxxx免费看久久| 国产亚洲精品va在线观看| 欧洲美女7788成人免费视频| 亚洲天堂男人天堂女人天堂| 欧美激情小视频| 国产精品入口福利| 中文字幕精品久久| 自拍偷拍亚洲欧美| 国产美女被下药99| 欧美一级大片在线免费观看| 亚洲精品在线不卡| 国产精品亚洲欧美导航| 日韩精品极品视频| 国产精品99久久久久久www| 欧美激情精品久久久久久免费印度| 久久视频免费在线播放| 国产日韩欧美日韩大片| 久久免费视频网站| 精品毛片三在线观看| 亚洲精品网站在线播放gif| 最好看的2019年中文视频| 欧美床上激情在线观看| 国产精品女主播视频| 国产一区二区三区在线| 久久久精品久久久| 国产日韩欧美成人| 久久99精品国产99久久6尤物| 91tv亚洲精品香蕉国产一区7ujn| 欧美中文字幕在线| 欧美另类极品videosbestfree| 亚洲人成网站免费播放| 亚洲第一区在线|