symfony表单与页面实现技巧
时间:2018-12-30 分类:PHP 作者:编程之家
本文实例讲述了symfony表单与页面 实现技巧。分享 给大家供大家参考。具体如下:
symfony开发很简洁,但是功能 的数量 仍然很缺乏。现在是时候进行一些askeet站点 与用户 之间的 交互了。而HTML交互的根本--除了起链接 --就是表单了。
这里我们的目标是允许用户 登陆,并在主页的问题列表中进行翻阅。这对于开发而言是很快的,并且可以让我们回忆起前面的内容 。
登陆表单
在测试数据中存在用户 ,但是程序却没有办法来进行验证。下面我们要在程序的每一个 页面 添加 一个 登陆表单。打开全局的布局文件 askeet/apps/frontend/templates/layout.PHP ,并且在到about的连接之前添加 下面的代码 行:
当前的布局将这些链接 放在web调试工具栏之后。要看到这些链接 ,点击'Sf'图标折叠起调试工具栏就可以看到了。
现在需要创建user模块。而question模块是在第二天生成 的,这一次我们只是叫symfony来创建模块框架,而我们将会自己来编写这些代码 。
这个框架包含一个 默 认的index动作与一个 indexSuccess.PHP 模板。删除 他们,因为我们并不需要他们。
创建user/login动作
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 模块:
<div class="form-row">
<label for="nickname">nickname:
<?php echo input_tag('nickname',$sf_params->get('nickname')) ?>
<div class="form-row">
<label for="password">password:
<?php echo input_password_tag('password') ?>
<?php echo input_hidden_tag('referer',$sf_request->getAttribute('referer')) ?>
<?php echo submit_tag('sign in') ?>
这个模块是我们第一次使用表单帮助器。这些Symfony函数 可以帮助我们自动 化编写表单标签 。form_tag()打开一从此标签 ,使用POST作为默 认的动作,并且指向作为参数传递的动作。input_tag()帮助器产生一个 标签 ,并且依据所传递的第一个 参数自动添加 一个 id属性 ;而默 认值则是由第二个参数得到。我们可以在Symfony一书的相关章节查找到更多的关于表单帮助器与他们所产生的HTML代码 的内容 。
这里的实质是当表单提交时则会调用 这个动作。所以我们返回来看一下这个动作。
处理表单提交
用下面的代码 来替换我们刚才所编写的登陆动作:
getRequest()->
getmethod () != sfRequest::POST)
{
//
dis play the form
$this->getRequest()->setAttribute('referer',$this->getRequest()->getReferer());
}
else
{
// handle the form submission
$nickname = $this->getRequestP
ara meter('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->getRequestPara meter('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一书的用户 证书一节对此进行了详细的解释。
这就是下面两行的目的:
getContext()->getUser()->setAuthenticated(true);
$this->getContext()->getUser()->addCredential('subscriber');
当nickname被识别后,不仅用户 数据被存放在会话属性 中,而且这个用户 也会被分配网站限制部分的访问权限。在明天我们将会看到如何限制验证用户 的程序访问。
添加 user/logo ut动作
关于->setAttribute()方法 还有最后一个 窍门:最后一个 参数(上面例子中的subscriber)定义了属性 存放的名字空间。一个 名字空间不仅允许一个 在另一个 名字空间存在的名字指定给一个 属性 ,而且可以使用一个 命令快速 移除所有这些属性 :
getUser()->setAuthenticated(false);
$this->getUser()->clearCredentials();
$this->getUser()->getAttributeHolder()->removeNamespace('subscriber');
$this->redirect('@homepage');
}
使用名字空间可以省去我们一个 一个 移除这些属性 的麻烦:这只是一行语句。
更新布局
当前这个布局即使用户 已经登陆仍然显示 一个 'login'链接 。让我们来修正这一点。在askeet/apps/frontend/templates/layout.PHP 文件 中,修改 我们在今天的指南开始时所修改 的代码 :
isAuthenticated()): ?>
getAttribute('nickname','','subscriber').' profile','user/profile') ?>
现在是时候进行测试了,我们可以显示 程序的任何一页,点击'login'链接 ,输入一个 可用的昵称('anonymous'为例)并且进行验证。如果窗口顶部的'login'变为'sign out',则我们所做的一切都是正确的。最后,试着注销来查看'login'链接 是否再次出现。
问题组织
随着数以千计的Symfony爱好者访问askeet网站,在主页上显示 的问题就会逐渐变多。为了避免变慢的请求速度,问题列的随意翻阅就成为必须解决 的问题。
Symfony为这一目的提供了一个 对象:sfPropelPager。他会封装到数据的请求,从而只会查询 当前页面 所显示 的记录。例如,如果一个 页面 初始化时每页只显示 10个问题,则到数据的请求只会限制为10个结果,并且会设置偏移来在页面 中进行匹配。
修改 question/list动作
在前面的练习中,我们看到了问题模块的显示 动作:
questions = QuestionPeer::doSelect(new Criteria());
}
我们将会修改 这个动作来向模板传递一个 sfPropelPager而不是传递一个 数组。同时,我们会依据感兴趣的数量 来对问题进行排序:
addDescendingOrderByColumn(QuestionPeer::INTERESTED_USERS);
$pager->setCriteria($c);
$pager->setPage($this->getRequestP
ara meter('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行:
fig::get('app_pager_homepage_max'));
这里的pager关键字是作为名字空间使用的,这也就是为什么在参数名字中出现的原因。我们可以在Symfony一书的配置一节中查看到更多的关于自定义 配置与命名自定义参数 规则的更多的内容 。
修改 listSuccess.PHP 模板
在listSuccess.PHP 模板中,将下面的代码 行:
替换为
getResults() as $question): ?>
从而页面 显示 存储在页面 中的结果列表。
在这 个模板中还需要做 另外一件事:页面 浏览。现在,模板所做的只是显示 前两个问题,但是我们应添加 到下一个 页面 的功能 ,以及回到前一个 页面 的功能 。要完成添加 这些功能 ,我们需要在模板后面添加 下面的代码 :
hav
eto Paginate()): ?>
PHP echo link_to('<','question/list?page='.$question_pager->getPrev
IoU sPage()) ?>
<?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; ?>
question_pager = QuestionPeer::getHomepagePager($this->getRequestP
ara meter('page',1));
}
addDescendingOrderByColumn(self::INTERESTED_USERS);
$pager->setCriteria($c);
$pager->setPage($page);
$pager->setPeerMethod('doSelectJoinUser');
$pager->init();
return $pager;
}
question = QuestionPeer::getQuestionFromTitle($this->getRequestP
ara meter('stripped_title'));
$this->forward404Unless($this->question);
}
add(QuestionPeer::STRIPPED_TITLE,$title);
return self::doSelectOne($c);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。