5日目はログイン処理の追加とページ処理です。

ログイン処理

ログインリンク追加

askeet/apps/frontend/templates/layout.php
about のリンクの前に入れる

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


デバッグモードだと symfony のツールバーにログインのリンクが隠れてしまう。[sf]ボタンをクリックするとデバッグ用のツールバーを隠すことができます。

ユーザモジュールの追加
symfony init-module frontend user

上記コマンドを実行すると下記のようなファイルが作成されます。

>> dir+      /home/askeet/apps/frontend/modules/user/actions
>> file+     /home/askeet/apps/frontend/modu.../user/actions/actions.class.php
>> dir+      /home/askeet/apps/frontend/modules/user/templates
>> file+     /home/askeet/apps/frontend/modu...user/templates/indexSuccess.php
>> file+     /home/askeet/test/functional/frontend/userActionsTest.php
>> tokens    /home/askeet/test/functional/frontend/userActionsTest.php
>> tokens    /home/askeet/apps/frontend/modu.../user/actions/actions.class.php
>> tokens    /home/askeet/apps/frontend/modu...user/templates/indexSuccess.php
ログインアクション

askeet/apps/frontend/modules/user/actions/actions.class.php

public function executeLogin()
{
  $this->getRequest()->setAttribute('referer', $this->getRequest()->getReferer());

  return sfView::SUCCESS;
}

これは仮の処理でとりあえずログインフォームを表示するだけの処理です。

ログインビュー

ログインフォームを表示するビューを作成します。
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>

さっそく先ほど作成したリンクからログインフォームを表示させてみると
Call to undefined function form_tag()
とエラーになった。Form ヘルパーが使えていないようです。
調べたところ

<?php use_helper('Form'); ?>

として使用するヘルパーを宣言しないといけないようです。バージョンが変わってデフォルトで使用できるヘルパーが変わったのでしょうか。

これでログインフォームが表示できるようになりました。

ログイン処理

先ほど仮に入れた処理を削除してログイン処理を実装します。
しかし、まだデータベースにパスワードフィールドがないので存在するユーザならパスワードが何でも認証します。
askeet/apps/frontend/modules/user/templates/loginSuccess.php

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'));
      }
    }
  }
}
ログアウト処理
public function executeLogout()
{
  $this->getUser()->setAuthenticated(false);
  $this->getUser()->clearCredentials();
  $this->getUser()->getAttributeHolder()->removeNamespace('subscriber');
  $this->redirect('@homepage');
}
レイアウトの変更

ログイン状態によってログインフォームへのリンク部分を変更するようにレイアウトを変更します。

<?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 ?>

ログインしていない場合は[sign in/register]を表示し、ログインしている場合は[sign out]とログインしているユーザ名を表示しリンク先をプロフィール表示画面にします。

実際にログインしてみる

テストデータを見るとユーザが3名ほど登録されています。その中から[fabpot]というユーザでログインしてみます。nicknameに[fabpot]、パスワードは空で[sign in]ボタンをクリックすると認証後に質問一覧ページにリダイレクトされました。

ページ処理

一覧表示アクションの修正

1ページに表示する質問数を取得してページ処理する処理を追加する
askeet/apps/frontend/modules/question/actions.class.php

public function executeIndex ()
{
  $pager = new sfPropelPager('Question', sfConfig::get('app_pager_homepage_max'));

  $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;
}
アプリケーション設定ファイルを変更

設定ファイル(app.yml) に1ページに表示する質問数を追加する
askeet/apps/frontend/config/app.yml

all:
  pager:
    homepage_max: 2

この設定を取得するには下記のようにします。

sfConfig::get('app_pager_homepage_max')

これで ’2′ が取得できる。この部分は1ページの質問数を設定している部分です。現在3つしか質問がないので1ページに2つの質問を表示することによりページング処理のテストを行います。

ビューの変更

一覧を表示する foreach の部分を下記に変更。これでページ処理された一覧を取得。

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

一覧の下にページナビゲーションを追加

<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>

ルーティングの変更

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 アクションが index だったり)のがどうもやりにくいので合せることにしました。

SVNレポジトリより routing.yml を落としてきてまずルーティングを合せました。
次に question コントローラの index アクションを list アクションに変更、indexSccess.php を listSuccess.php に変更。
これですっきりしました。

関連する投稿