413 12
发新话题
打印

symfony 项目实践

symfony 项目实践

symfony 项目实践

原文:http://www.symfony-project.com/tutorial/my_first_project.html

转载注明:PHP开发资源网(http://www.phpres.com)

看完对Symfony的介绍,你想要体验一下它的功能?就让我们做一个一小时可完成的全功能网站。 你可以叫它卖书的程式,或是,你也可以叫他网誌(部落格)。就让我们开始吧!

我们将假设你已经装好了apache/PHP5(如果你想快一点,你可用xampp/lampp)。

你也需要一个SQLite。目前预设已经和PHP5整合好了。然而,若是PHP 5.1.0,你必须要用php.ini开启PHP对SQLite的支持(详情)。

為了加快速度,我们用了symfony sandbox。它是个空的symfony专案,且包含了所有的symfony函式库,而且最基础的设定也完备了。用sandbox的最大好处,就是你可以马上体验symfony 。

下载sandbox。然后在你的网站根目录解压缩。你可参考readme已得到更多的资讯。解开后的档案结构应该像这样:
复制内容到剪贴板
代码:
www/
  sf_sandbox/
    apps/
      frontend/
    batch/
    cache/
    config/
    data/
      sql/
    doc/
      api/
    lib/
      model/
    log/
    test/
    web/
      css/
      images/
      js/
      uploads/
这表示sf_sandbox已经有了前端程式,你可在你的网址列打上
复制内容到剪贴板
代码:
http://localhost/sf_sandbox/web/index.php/
你将看到一个恭喜的网页:


注意:如果你看不到这个恭禧你安装成功的网页,请你检查php.ini这个配置文件。找这个设定值“magic_quotes_gpc”把它设定成off. 如需要更多的帮忙,请参考安装论坛,那里有超多特殊的状况,被一一解决。


你可以安装symfony在你自己喜欢的目录下。然后设定你的网站指向它。或是设成虚拟网站或是别名网站,symfony的书有详细的章节介绍,请参考symfony installation, project creation and file structure这几章。

[ 本帖最后由 symfony项目 于 2007-6-24 08:59 编辑 ]

TOP

初始化资料模型

当然,一般的网志,可以处理贴文的。然后你也可以在其上加些註解评论。在目录sf_sandbox/config/新增一个结构设定档schema.yml,然后贴上如下的内文。
复制内容到剪贴板
代码:
propel:
  weblog_post:
    _attributes: { phpName: Post }
    id:
    title:       varchar(255)
    excerpt:     longvarchar    body:        longvarchar
    created_at:  weblog_comment:
    _attributes: { phpName: Comment }
    id:
    post_id:
    author:      varchar(255)
    email:       varchar(255)
    body:        longvarchar
    created_at:
这个设定档用的是YAML文法,它是一个很简单的语言,用类似XML的树状阶层的架构来定义资料模型(资料表)。更进一步,它的读写比XML还快。这唯一要注意的是,缩排是有意义的,且要避免使用TAB键,所以请记住用空白键(SPACE)来表示少缩排。

你可以在configuration chapter这章,找到更多关於YAML和symfony的设定须知。

这个结构档描述在网志程式里所需要用到的两个资料表。Post和Comment是未来将会產生相对应的类别。存档,然后进入指令列。进到目录sf_sandbox/,然后键入:
引用:
注意:在*nix平台,你可能是用./symfony.sh而不是键入symfony
一些类别会产生在这个目录sf_sandbox/lib/model/,它们是物件/关係映射(object-relational mapping)的产物。这些类别的好处是我们可以用物件导向的方式而不是下SQL的INSERT/UPDATE指令来存取关联性资料库。Symfony使用Propel函式库来来达到此目的。我们将叫这些物件为模型(model)。(更多关于模型的说明)

你现在可以在指令列,输入
复制内容到剪贴板
代码:
$ symfony propel-build-sql
一个schema.sql 档產生在sf_sandbox/data/sql/。里面的SQL句子可以產生一个资料库,里面含这两资料表。你可以下指令或用WEB界面(phpMyAdmin)在MYSQL产生资料库。(在这章model也有讲到)。幸运地symfony sandbox 已经设定好直接可用SQLite(轻便的档案型资料库)。所以不用再做一些初始设定。预设的状况下,sf_sandbox专案将使用sf_sandbox/data/目录下的一个sandbox.db。如果你要在这个档案型资料库建资料表。你可以键入
复制内容到剪贴板
代码:
$ symfony propel-insert-sql
注意:在这里有警告讯息也不用紧张,这是正常的,insert-sql的动作是先移除资料很再建立资料表,第一次做之前,当然没资料表可移除。

TOP

创建程序棚架(scaffolding)

众所周知,一个基本的网志可让用户建立,检索,更新,删除贴子和留言(CRUD)。考虑到你还是Symfony的新手,你将不会要求从零开始写Symfony的代码,而是让Symfony帮你创建CRUD的棚架。棚架建好之后,你可以根据需要而修改CRUD的代码。输入:
复制内容到剪贴板
代码:
$ symfony propel-generate-crud frontend post Post
$ symfony propel-generate-crud frontend comment Comment
注意: 确定你在Symfony专案的根目录下执行这些指令

现在你建立了两个模块(post and comment),可让你支配Post和Comment类的对象。一个模块通常用来代表一个或一组有相似功能的网页。你新建两个模块位于sf_sandbox/apps/frontend/modules/目录里。相应的,它们可以访问这两个模块通过以下地址:
复制内容到剪贴板
代码:
http://localhost/sf_sandbox/web/frontend_dev.php/post
http://localhost/sf_sandbox/web/frontend_dev.php/comment
点击‘create‘添加几个测试贴:





你可以在scaffoldingstructure找到更多关于棚架和symfony专案构架的说明。

注意:以上的两个地址的运行脚本 - 在Symfony里称为front controller - 由index.php变为frontend_dev.php。两个脚本都执行一样的运用程序,区别是它们使用不同的执行参数。frontend_dev.php使用‘开发环境‘的参数,目的在于提供一系列的调试工具,例如‘debug toolbar‘位于屏幕的右上角。这就是为什么frontend_dev.php在处理页面的时候比index.php要慢。index.php则使用‘生产环境‘的参数。如果你在开发时需要用到用‘生产环境‘,只需把frontend_dev.php改为index.php,然后清除缓存:
复制内容到剪贴板
代码:
$ symfony clear-cache
更多关于运行环境的说明

TOP

修改模板

要在我们新建两个模块之间导航,我们的网页需共享超连结。打开公用模板sf_sandbox/apps/frontend/templates/layout.php,把<body>之间的内容修改为:
复制内容到剪贴板
代码:
<div id="container" style="width:600px;margin:0 auto;border:1px solid grey;padding:10px">
  <div id="navigation" style="display:inline;float:right">
    <ul>
      <li>k</li>
      <li></li>
    </ul>
  </div>
  <div id="title">
    <h1>kk</h1>
  </div>

  <div id="content" style="clear:right">
    kk
  </div>
</div>
请原谅不精心的设计和使用inline CSS,一个小时的时间并不是很充裕。






你可以修改页面的标题。打开转案的配置文件sf_sandbox/apps/frontend/config/view.yml, 找出有title的一行,修改为:
复制内容到剪贴板
代码:
default:
  http_metas:
    content-type: text/html; charset=utf-8

  metas:
    title:        The best weblog ever
    robots:       index, follow
    description:  symfony project
    keywords:     symfony, project
    language:     en
你目前的主页使用默认的模版(template)和模块(module),位于Symfony框架目录下,而不在你的专案目录下。如果要覆盖(override)它,你必须建立自己的默认模块。输入:
复制内容到剪贴板
代码:
$ cd apps/frontend/modules
$ mkdir default
$ cd default
$ mkdir templates
$ cd templates
新建文件indexSucess.php,加入以下的内容:
复制内容到剪贴板
代码:
<h1>Welcome to my swell weblog</h1>
<p>You are the <?php echo rand(1000,5000) ?>th visitor today.</p>
导航到以下地址测试新的页面:
复制内容到剪贴板
代码:
http://localhost/sf_sandbox/web/frontend_dev.php/





测试:建立一个贴,然后测试回复。
更多关于模版视图设置的说明

TOP

把数据从动作传递到模版

这一节,我们要做的是在贴的下面显示回复。 首先,你必须编辑动作(action)。打开sf_sandbox/apps/frontend/modules/post/actions/actions.class.php,找到函数executeShow(),加入下面的四行代码:
复制内容到剪贴板
代码:
public function executeShow ()
{
  $this->post = PostPeer::retrieveByPk($this->getRequestParameter('id'));

  $c = new Criteria();
  $c->add(CommentPeer::POST_ID, $this->getRequestParameter('id'));
  $c->addAscendingOrderByColumn(CommentPeer::CREATED_AT);
  $this->comments = CommentPeer::doSelect($c);

  $this->forward404Unless($this->post instanceof Post);
复制内容到剪贴板
代码:
Criteria和Peer是Propel的对象关系映射(object-relational mapping)的一部分。总之,这四行代码将会从SQL中调出与Post相关联的Comment(Post指定在URL的id参数)。$this→comments这行主要是让与动作相对应的模版读取$comments里的数据。下一步我们就可以修改模版显示数据了。打开sf_sandbox/apps/frontend/modules/post/templates/showSuccess.php,在最后一行加入:
复制内容到剪贴板
代码:
...
<?php use_helper('Text') ?>
<?php use_helper('Date') ?>

<hr />
<?php if($comments) : ?> <p><?php echo count($comments) ?> comment<?php if(count($comments)>1) : ?>s<?php endif ?> to this post.</p>
  <?php foreach ($comments as $comment): ?> <p><em>posted by <?php echo $comment->getAuthor() ?> on <?php echo format_date($comment->getCreatedAt()) ?></em></p>
    <div class="comment" style="margin-bottom:10px;">
      <?php echo simple_format_text($comment->getBody()) ?>
    </div>   
  <?php endforeach ?>
<?php endif ?>


本页使用了两个新的由Symfony提供的函数(format_date()和simple_format_text())。在Symfony里这些函数称为助手(helpers),原因是它们能够提供一些很便利的功能。为你的第一个贴添加一个新的回复,然后查看:
复制内容到剪贴板
代码:
http://localhost/sf_sandbox/web/frontend_dev.php/post/show?id=1




你可以在命名协议找到更多关于动作和模版的联系,或查看textdata的说明。

TOP

添加与另一个资料表相关联的档案

你可以依据Post的Id添加档案,但这不是用户界面友好设计的做法。让我们修改这一不便利之处。另外,当用户回复后,别忘了把他重定向到原来的贴。 首先,打开modules/post/templates/showSuccess.php模板,在最后一行加入:

复制内容到剪贴板
代码:
<?php echo link_to('Add a comment','comment/create?post_id='.$post->getId()) ?>


link_to()是一个助手,它建立一个超链接指向comment模块的create动作,目的是让你可以从看贴的页直接回复。下一步,打开imodules/comment/templates/editSuccess.php,把这几行:

复制内容到剪贴板
代码:
<tr>
  <th>Post*:</th>
  <td><?php echo object_select_tag($comment, 'getPostId', array (
  'related_class' => 'Post',
)) ?></td>
</tr>


更替为:

复制内容到剪贴板
代码:
<?php if ($sf_request->hasParameter('post_id')): ?>
  <?php echo input_hidden_tag('post_id',$sf_request->getParameter('post_id')) ?>
<?php else: ?>
  <tr>
    <th>Post*:</th>
    <td><?php echo object_select_tag($comment, 'getPostId', array (
    'related_class' => 'Post',
    )) ?></td>
  </tr>
<?php endif ?>



comment/create页的表单指向comment/update的动作,而且当用户提交表单之后,comment/update的动作会把页面重定向到comment/show(这是CRUDs的默认处理方式)。对我们的网志来说,这意味着在添加回复后,只有刚回复的comment显示在页面。为了达到户界面友好的设计,在用户回复后,把贴和回复显示在同一页面。打开modules/comment/actions/actions.class.php,把executeupdate()修改为:
复制内容到剪贴板
代码:
public function executeUpdate ()
{
  if (!$this->getRequestParameter('id', 0))
  {
    $comment = new Comment();
  }
  else
  {
    $comment = CommentPeer::retrieveByPk($this->getRequestParameter('id'));
    $this->forward404Unless($comment);
  }   

  $comment->setId($this->getRequestParameter('id'));
  $comment->setPostId($this->getRequestParameter('post_id'));
  $comment->setAuthor($this->getRequestParameter('author'));
  $comment->setEmail($this->getRequestParameter('email'));
  $comment->setBody($this->getRequestParameter('body'));

  $comment->save();

  return $this->redirect('post/show?id='.$comment->getPostId());
}
现在,用户能在回复后回到原来的界面。到此为止,你已完成了一个基本的网志。
你可以在这里找到更多关于动作的说明

TOP

表单验证

用户可以回贴,但是,如果有谁提交空白的表单,数据库的质量将会受到殃及。避免此类情况发生,在sf_sandbox/apps/frontend/modules/comment/validate/目录下创建一个新的文件update.yml,加入:
复制内容到剪贴板
代码:
methods:
  post:           [author, email, body]
  get:            [author, email, body]

fillin:
  activate:       on

names:
  author:
    required:     Yes
    required_msg: The name field cannot be left blank

  email:  
    required:     No
    validators:   emailValidator

  body:
    required:     Yes
    required_msg: The text field cannot be left blank

emailValidator:
  class:          sfEmailValidator
  param:
    email_error:  The email address is not valid.
注意:复制时务必保留原来的格式,文件务虚以methodsm开头,不能有空格

启动fillin可使表单在验证失败的情况下,自动导入用户上一次输入的数据。names定义表单的验证规则。

在默认情况下,当验证失败,控制器(controller)将会把用户转updateError.php模板。较可取的做法是当验证失败时,在同一页面显示表单和失败原因。打开modules/comment/actions/actions.class.php,加入函数:
复制内容到剪贴板
代码:
public function handleError()
{
  $this->forward('comment', 'create');
}
打开modules/comment/templates/editSuccess.php模版,在第一行插入:
复制内容到剪贴板
代码:
<?php if ($sf_request->hasErrors()): ?>  
  <div id="errors" style="padding:10px;">
    Please correct the following errors and resubmit:
    <ul>
    <?php foreach($sf_request->getErrors() as $error): ?>
      <li><?php echo $error ?></li>
    <?php endforeach ?>
    </ul>
  </div>
<?php endif ?>
你完成了一个具有 鲁棒性(robust)的表单。






更多关于表单验证的说明

TOP

修改URL

我们可以让我们网志的URL更加亲和用户和搜索引擎。就用贴的标题作为URL吧。
标题为URL存在一个问题 - 标题可含有特殊字符如空格。你可以转换字符,但在有空格的情况下会产生不美观的URL(例如%20)。所以最好是在Post模型(model)中加入一个清理标题的函数。打开sf_sandbox/lib/model/Post.php,添加函数:
复制内容到剪贴板
代码:
public function getStrippedTitle()
{
  $result = strtolower($this->getTitle());

  // strip all non word chars
  $result = preg_replace('/\W/', ' ', $result);

  // replace all white space sections with a dash
  $result = preg_replace('/\  /', '-', $result);

  // trim dashes
  $result = preg_replace('/\-$/', '', $result);
  $result = preg_replace('/^\-/', '', $result);

  return $result;
}
现在你能为post模块建立一个permalink动作. 打开modules/post/actions/actions.class.php,加入函数:
复制内容到剪贴板
代码:
public function executePermalink()
{
  $posts = PostPeer::doSelect(new Criteria());
  $title = $this->getRequestParameter('title');
  foreach ($posts as $post)
  {
    if ($post->getStrippedTitle() == $title)
    {
      break;
    }
  }
  $this->forward404Unless($post);

  $this->getRequest()->setParameter('id', $post->getId());

  $this->forward('post', 'show');
}
打开模版modules/post/templates/listSuccess.php, 把显示id的部分去掉,且把
复制内容到剪贴板
代码:
<td><?php echo $post->getTitle() ?></td>
修改为:
复制内容到剪贴板
代码:
<td><?php echo link_to($post->getTitle(), '/'.$sf_last_module.'/permalink?title='.$post->getStrippedTitle()) ?></td>
最后,打开sf_sandbox/apps/frontend/config/routing.yml,加入:
复制内容到剪贴板
代码:
list_of_posts:
  url:   /latest_posts
  param: { module: post, action: list }

post:
  url:   /weblog/:title
  param: { module: post, action: permalink }
打开网页测试新的URL。





更多关于智慧URL的说明

TOP

整理前端程序

此步主要是限制用户的权限 - 只给用户阅读的权力。
打开modules/post/templates/showSuccess.php模版,删除这行:
复制内容到剪贴板
代码:
<?php echo link_to('edit', 'post/edit?id='.$post->getId()) ?>
同样地,打开modules/post/templates/listSuccess.php模版,删除:
复制内容到剪贴板
代码:
<?php echo link_to('create', 'post/create') ?>
打开modules/post/actions/actions.class.php,删除函数:
复制内容到剪贴板
代码:
* executeCreate
* executeEdit
* executeUpdate
* executeDelete
到此为止,用户只拥有阅读的权限了。

TOP

制作后端程序

让我们制作一个可让我们发帖的后端程序。在转案的根目录下(sf_sandbox),输入:
复制内容到剪贴板
代码:
$ symfony init-app backend
$ symfony propel-init-admin backend post Post
$ symfony propel-init-admin backend comment Comment
这一次,我们用管理生成器(Admin generator),它比CRUD更强大且具更多的功能。

打开apps/backend/template/layout.php模版,加入共享导航链接:

复制内容到剪贴板
代码:
<div id="navigation">
  <ul style="list-style:none;">
    <li><?php echo link_to('Manage posts', 'post/list') ?></li>
    <li><?php echo link_to('Manage comments', 'comment/list') ?></li>
  </ul>
</div>      
<div id="content">
  <?php echo $sf_content ?>
</div>



注意:Note: Because you are using a sandbox, you also need to copy the sf_sandbox/web/sf/images/sf_admin/ directory in a sf/images/sf_admin/ directory in your web root folder (this is due to image paths in CSS stylesheets).(这段不是很明确,有待翻译)


你能访问刚做好的后端程序 - 以调试环境(develop environment):
复制内容到剪贴板
代码:
http://localhost/sf_sandbox/web/backend_dev.php/post





使用Admin generator最大的好处是通过配置文件,你可以轻易地制作自定义方案(configuration file)。 修改backend/modules/post/config/generator.yml:
复制内容到剪贴板
代码:
generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Post
    theme:            default
    fields:
      title:          { name: Title }
      excerpt:        { name: Exerpt }
      body:           { name: Body }
      nb_comments:    { name: Comments }
      created_at:     { name: Creation date }
    list:
      title:          Post list
      layout:         tabular
      display:        [=title, excerpt, nb_comments, created_at]
      object_actions:
        _edit:        -
        _delete:      -
      max_per_page:   5
      filters:        [title, created_at]
    edit:  
      title:          Post detail        
      fields:
        title:        { type: input_tag, params: size=53 }
        excerpt:      { type: textarea_tag, params: size=50x2 }
        body:         { type: textarea_tag, params: size=50x10 }
        created_at:   { type: input_date_tag, params: rich=on }
以上的Post model有一列nb_comments。我们的模型(model)没有提供这一函数。打开sf_sandbox/lib/model/Post.php模型,加入下列函数:
复制内容到剪贴板
代码:
public function getNbComments()
{
  return count($this->getComments());
}
复制内容到剪贴板
代码:
打开页面,更新(refresh),测试刚完成的模块。

TOP

 413 12
发新话题