搜索
首页后端开发php教程symfony表单与页面实现技巧_PHP

本文实例讲述了symfony表单与页面实现技巧。分享给大家供大家参考。具体如下:

symfony开发很简洁,但是功能的数量仍然很缺乏。现在是时候进行一些askeet站点与用户之间的交互了。而HTML交互的根本--除了起链接--就是表单了。

这里我们的目标是允许用户登陆,并在主页的问题列表中进行翻阅。这对于开发而言是很快的,并且可以让我们回忆起前面的内容。

登陆表单

在测试数据中存在用户,但是程序却没有办法来进行验证。下面我们要在程序的每一个页面添加一个登陆表单。打开全局的布局文件askeet/apps/frontend/templates/layout.php,并且在到about的连接之前添加下面的代码行:

代码如下:

  • 当前的布局将这些链接放在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模块:

    代码如下:


     
     


     
     

       
        get('nickname')) ?>
     

     
     

       
       
     

     
     

     
      getAttribute('referer')) ?>
     
     

    这个模块是我们第一次使用表单帮助器。这些Symfony函数可以帮助我们自动化编写表单标签。form_tag()打开一从此标签,使用POST作为默认的动作,并且指向作为参数传递的动作。input_tag()帮助器产生一个标签,并且依据所传递的第一个参数自动添加一个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文件中,修改我们在今天的指南开始时所修改的代码:

    代码如下:

    isAuthenticated()): ?>
     


  •  
  • getAttribute('nickname', '', 'subscriber').' profile', 'user/profile') ?>


  •  

  • 现在是时候进行测试了,我们可以显示程序的任何一页,点击'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模板中,将下面的代码行:

    代码如下:

    替换为

    代码如下:

    getResults() as $question): ?>

    从而页面显示存储在页面中的结果列表。

    添加页面浏览

    在这个模板中还需要做另外一件事:页面浏览。现在,模板所做的只是显示前两个问题,但是我们应添加到下一个页面的功能,以及回到前一个页面的功能。要完成添加这些功能,我们需要在模板后面添加下面的代码:

    代码如下:


    haveToPaginate()): ?>
     
      getPreviousPage()) ?>
     
      getLinks() as $page): ?>
        getPage(), $page, 'question/list?page='.$page) ?>
        getCurrentMaxLink()) ? '-' : '' ?>
     
     
      ', 'question/list?page='.$question_pager->getNextPage()) ?>
      getLastPage()) ?>

    这段代码利用了sfPropelPager对象的各种方法,以及->haveToPaginate(),这个函数只有在请求的结果数目超过了页面尺寸时才会返回真;而->getPreviousPage(),->getNextPage(),->getLastPage()都具有明显示的意义;->getLinks()函数提供了一个页面号的数组;而->getCurrentMaxLink()函数返回最后的页面号。

    这个例子同时显示了一个Symfony链接帮助器:link_to_unless()会在作为第一个参数的测试为假的情况下输出一个常规link_to(),否则会输出一个非链接的文本,并使用简单的包装。

    我们测试这个页面了吗?我们应进行测试。直到我们用我们自己的眼睛来验证,这个修改才算结束。要进行测试,打开在第三天所创建的测试数据文件,并且为要显示的页面浏览添加一些问题。重新运行导入数据批处理文件,然后再一次请求主页。

    为子页添加路由规则

    默认情况下,页面规则如下:

    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的内容:

    代码如下:

    popular question

    $question_pager)) ?>

    希望本文所述对大家的symfony框架程序设计有所帮助。

  • 声明
    本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
    PHP和Python:解释了不同的范例PHP和Python:解释了不同的范例Apr 18, 2025 am 12:26 AM

    PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

    PHP和Python:深入了解他们的历史PHP和Python:深入了解他们的历史Apr 18, 2025 am 12:25 AM

    PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

    在PHP和Python之间进行选择:指南在PHP和Python之间进行选择:指南Apr 18, 2025 am 12:24 AM

    PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

    PHP和框架:现代化语言PHP和框架:现代化语言Apr 18, 2025 am 12:14 AM

    PHP在现代化进程中仍然重要,因为它支持大量网站和应用,并通过框架适应开发需求。1.PHP7提升了性能并引入了新功能。2.现代框架如Laravel、Symfony和CodeIgniter简化开发,提高代码质量。3.性能优化和最佳实践进一步提升应用效率。

    PHP的影响:网络开发及以后PHP的影响:网络开发及以后Apr 18, 2025 am 12:10 AM

    PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

    PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?Apr 17, 2025 am 12:25 AM

    PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

    PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?Apr 17, 2025 am 12:24 AM

    PHP中使用clone关键字创建对象副本,并通过\_\_clone魔法方法定制克隆行为。1.使用clone关键字进行浅拷贝,克隆对象的属性但不克隆对象属性内的对象。2.通过\_\_clone方法可以深拷贝嵌套对象,避免浅拷贝问题。3.注意避免克隆中的循环引用和性能问题,优化克隆操作以提高效率。

    PHP与Python:用例和应用程序PHP与Python:用例和应用程序Apr 17, 2025 am 12:23 AM

    PHP适用于Web开发和内容管理系统,Python适合数据科学、机器学习和自动化脚本。1.PHP在构建快速、可扩展的网站和应用程序方面表现出色,常用于WordPress等CMS。2.Python在数据科学和机器学习领域表现卓越,拥有丰富的库如NumPy和TensorFlow。

    See all articles

    热AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智能驱动的应用程序,用于创建逼真的裸体照片

    AI Clothes Remover

    AI Clothes Remover

    用于从照片中去除衣服的在线人工智能工具。

    Undress AI Tool

    Undress AI Tool

    免费脱衣服图片

    Clothoff.io

    Clothoff.io

    AI脱衣机

    AI Hentai Generator

    AI Hentai Generator

    免费生成ai无尽的。

    热门文章

    R.E.P.O.能量晶体解释及其做什么(黄色晶体)
    1 个月前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳图形设置
    1 个月前By尊渡假赌尊渡假赌尊渡假赌
    威尔R.E.P.O.有交叉游戏吗?
    1 个月前By尊渡假赌尊渡假赌尊渡假赌

    热工具

    MinGW - 适用于 Windows 的极简 GNU

    MinGW - 适用于 Windows 的极简 GNU

    这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

    DVWA

    DVWA

    Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

    SecLists

    SecLists

    SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

    SublimeText3 Mac版

    SublimeText3 Mac版

    神级代码编辑软件(SublimeText3)

    记事本++7.3.1

    记事本++7.3.1

    好用且免费的代码编辑器