Symfony之mvc学习笔记

学习网址:
http://symfony.com/doc/current/index.html
(1)Router
完美的url对于任何一个重要的web应用,都是相当必要的.
路由的灵活性也是相当重要的.当霓需要修改一个url的时候,有很多地方需要随之修改,但是你用了symfony的路由,改变起来就简单了.
举例:
路由是一个从url路径到controller的映射.例如,你想匹配所有的url路径,像/blog/my-post 或者 /blog/all-about-symfony
然后把他们发送到controller
//路由注释的方式
<?php
namespace AppBundle\Controller;


use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;


class BlogController extends Controller
{
    /**
     * Matches /blog exactly
     *
     * @Route("/blog", name="blog_list")
     */
    public function listAction()
    {
        // ...
    }


    /**
     * Matches /blog/*
     *
     * @Route("/blog/{slug}", name="blog_show")
     */
    public function showAction($slug)
    {
        // $slug will equal the dynamic part of the URL
        // e.g. at /blog/yay-routing, then $slug='yay-routing'


        // ...
    }
}
//yml文件配置的方式
# app/config/routing.yml
blog_list:
    path: /blog
    defaults: {_controller: AppBundle:Blog:list}


blog_show:
    path: /blog/{slug}
    defaults: {_controller: AppBundle:Blog:show}
如果链接到/blog,走listAction
如果链接/blog/*,走showAction,如果url是:/blog/yay-routing,那么$slug和yay-routing相等


无论什么时候,当{placeholder}存在于你的url中,这一部分就成了一个通配符:匹配任何值.


每一个路由也拥有一个内部的名字:blog_list和blog_show.可以任意命名,但要唯一,并且没有其他的意义,最后,你可以
用它去生成urls.


添加通配符的要求
想象blog_list路由将包含blog posts的分页列表,通过url:/blog/2和/blog/3的形式到第二页第三页,
如果把路由改成/blog/{page},是有问题的:
blog_list: /blog/{page} 匹配/blog/*;
blog_snow: /blog/{slug} 也是匹配/blog/*的
当两个路由匹配相同的名字的时候,加载第一个路由.不幸的是,这意味着/blog/yay-routing将匹配/blog_list,
这不是我们希望看到的.
为了解决这个问题,添加一个{page}通配符的要求限制只能匹配数字.
/**
 * 注释方法
 * @Route("/blog/{page}", name="blog_list", requirements={"page": "\d+"})
 */
//yml文件配置
# app/config/routing.yml
blog_list:
    path:      /blog/{page}
    defaults:  { _controller: AppBundle:Blog:list }
    requirements:
        page: '\d+'


给通配符一个默认值
在前面的例子中,blog_list有一个路径/blog/{page}.如果用户走/blog/1路径,匹配,但是走/blog就找不到匹配了.
因此,当你给路由添加了一个通配符的时候,通配符必须有一个值.
因此,我们怎样才能让/blog_list再次匹配/blog呢?答案是,给通配符添加一个默认的值.
/**
 * @Route("/blog/{page}", name="blog_list", requirements={"page": "\d+"})
 */
public function listAction($page = 1)
{
    // ...
}
# app/config/routing.yml
blog_list:
    path:      /blog/{page}
    defaults:  { _controller: AppBundle:Blog:list, page: 1 }
    requirements:
        page: '\d+'
现在,当用户访问/blog,blog_list路由旧爱那个匹配,并且$page有一个默认的值1.


高级的路由例子
有了以上的一切,我们看看一个高级的路由例子
class ArticleController extends Controller
{
    /**
     * @Route(
     *     "/articles/{_locale}/{year}/{title}.{_format}",
     *     defaults={"_format": "html"},
     *     requirements={
     *         "_locale": "en|fr",
     *         "_format": "html|rss",
     *         "year": "\d+"
     *     }
     * )
     */
    public function showAction($_locale, $year, $title)
    {
    }
}
# app/config/routing.yml
article_show:
  path:     /articles/{_locale}/{year}/{title}.{_format}
  defaults: { _controller: AppBundle:Article:show, _format: html }
  requirements:
      _locale:  en|fr
      _format:  html|rss
      year:     \d+
真如你所看到的,这个路由只能匹配通配符{_locale}是en或者fr,{_format}是html或者rss,{year}是
数字的情况.这个路由也展示了在通配符之间如何用一个点(.)代替一个斜线.


控制器
控制器是你创建的php方法,用来从symfony的请求对象中读取信息,创建和返回response对象.相应可以是
html页面,json,xml,一个文件下载,一个重定向,404错误页面,或者其他你可以想象到的.控制器执行任意的
你的应用需要渲染页面内容的逻辑.


看看通过观察操作里的symfony控制器是多么简单.这里渲染一个页面,答应出一个lucky随机的数字
class LuckyController
{
    /**
     * @Route("/lucky/number")
     */
    public function numberAction()
    {
        $number = mt_rand(0, 100);


        return new Response(
            '<html><body>Lucky number: '.$number.'</body></html>'
        );
    }
}
但是在现实世界中,你的控制器很可能为了创建一个response去做很多的工作.它也许会从请求中读取信息,
加载数据库资源,发送邮件或者在缓存中设置信息.但是在所有的情况下,控制器最终将响应对象传递给客户端.


基础控制器class和services
为了简单,symfony带有一个可选的基础控制器类.如果你继承它,不会改变你的控制器的任何工作,但是,你
将能够访问多个帮助方法和服务容器:一个让你获取系统中非常游泳的对象的类似数组对象.这些有用的对象被称为服务,
拥有服务对象的symfony ships可以解析Twig模板,其他的可以打印日志信息等等.
// src/AppBundle/Controller/LuckyController.php
namespace AppBundle\Controller;


use Symfony\Bundle\FrameworkBundle\Controller\Controller;


class LuckyController extends Controller
{
    // ...
}


生成URLS
generateUrl()方法仅仅是一个辅助方法用来为提供一个路由生成URL
$url = $this->generateUrl('blog_show', array('slug' => 'slug-value'));


重定向
如果你想重定向用户到另一个页面,用redirectToRoute()和redirect()方法:
public function indexAction()
{
    // redirect to the "homepage" route
    return $this->redirectToRoute('homepage');


    // do a permanent - 301 redirect
    return $this->redirectToRoute('homepage', array(), 301);


    // redirect to a route with parameters
    return $this->redirectToRoute('blog_show', array('slug' => 'my-page'));


    // redirect externally
    return $this->redirect('http://symfony.com/doc');
}
redirectToRoute相当于
use Symfony\Component\HttpFoundation\RedirectResponse;


public function indexAction()
{
    return new RedirectResponse($this->generateUrl('homepage'));
}


解析模板
如果你正在操作HTML,你需要去渲染一个模板,render()方法可以渲染一个模板,并且可以将返回数据对象帮你放到渲染内容中.
return $this->render('lucky/number.html/twig', array('name' => $name));


捕获其他的服务
symfony打包了很多游泳的对象,称为服务.这些服务被用于渲染模板,发送邮件,查询数据库以及其他你能想到
的工作.当你安装了一个新的bundle,它可能带来更多的服务.
当继承了基础的控制器类,你可以通过get()方法获取任何symfony服务.下面是一些常用的服务:
$templating = $this->get('templating');
$router = $this->get('router');
$mailer = $this->get('mailer');
使用$ php bin/console debug:container命令可以列出所有的服务.
获取容器的配置参数,可以用getParameter()方法:
$from = $this->getParameter('app.mailer.from');


管理错误和404页面
当事物没有找到,你需要进行http协议的友好展示,并且返回一个404响应.去做这些,你将抛出一个一查的特殊类型
,如果你继承了基础的控制器类,按照下面的操作:
public function indexAction()
{
    // retrieve the object from database
    $product = ...;
    if (!$product) {
        throw $this->createNotFoundException('The product does not exist');
    }


    return $this->render(...);
}
createNotFoundException()方法仅仅是一个传见特殊NotFoundHttpException对象的快捷方法,根本是触发
了symfony内部的404http响应.
当然,你可以在你的控制器中自由的抛出任何异常,symfony将立即返回一个500http相应码.
throw new \Exception('Something went wrong!');


请求对象作为一个控制器参数
如果你想读取查询参数,抓取一个请求头或者获取上传文件怎么办?所有的信息被出存在symfony的请求对象中,
在你的控制器中获取它,仅仅作为一个参数添加它.并且用"request"class类型提示.
use Symfony\Component\HttpFoundation\Request;


public function indexAction($firstName, $lastName, Request $request)
{
    $page = $request->query->get('page', 1);


    // ...
}


管理session
symfony提供了一个非常棒的session对象,你可以用来存储用户请求之间的信息.默认情况下,symfony通过使用
php的会话将属性存储在cookie中.
检索session,在request对象上调用getSession()方法.这个方法返回一个从session中存储和获取信息的简单方法的SessionInterface:
use Symfony\Component\HttpFoundation\Request;


public function indexAction(Request $request)
{
    $session = $request->getSession();


    // store an attribute for reuse during a later user request
    $session->set('foo', 'bar');


    // get the attribute set by another controller in another request
    $foobar = $session->get('foobar');


    // use a default value if the attribute doesn't exist
    $filters = $session->get('filters', array());
}
存储的属性保留在该用户会话的其余部分的会话中。


动画信息
你也可以存储特殊信息,称为"flash"messages,在用户的session中.通过设计,flash信息意味着只能被准确
的使用一次:当你检索他们后,他们会立即从session中消失.这个特征使得flash信息特别适合存储用户通知.


例如,想象你正在处理一个表单提交
use Symfony\Component\HttpFoundation\Request;


public function updateAction(Request $request)
{
    // ...


    if ($form->isValid()) {
        // do some sort of processing


        $this->addFlash(
            'notice',
            'Your changes were saved!'
        );
        // $this->addFlash is equivalent to $request->getSession()->getFlashBag()->add


        return $this->redirectToRoute(...);
    }


    return $this->render(...);
}
处理完请求后,控制器在session中设置了一个flash信息然后重定向.这个信息的key,可以自定义:你可以通过这个
key去检索key对应的信息.
在模板中读取flash信息:
{# app/Resources/views/base.html.twig #}
{% for flash_message in app.session.flashBag.get('notice') %}
    <div class="flash-notice">
        {{ flash_message }}
    </div>
{% endfor %}


请求和响应对象
如前所述,该框架将请求对象传递给具有该请求类的类型的任何控制器参数:
use Symfony\Component\HttpFoundation\Request;


public function indexAction(Request $request)
{
    $request->isXmlHttpRequest(); // is it an Ajax request?


    $request->getPreferredLanguage(array('en', 'fr'));


    // retrieve GET and POST variables respectively
    $request->query->get('page');
    $request->request->get('page');


    // retrieve SERVER variables
    $request->server->get('HTTP_HOST');


    // retrieves an instance of UploadedFile identified by foo
    $request->files->get('foo');


    // retrieve a COOKIE value
    $request->cookies->get('PHPSESSID');


    // retrieve an HTTP request header, with normalized, lowercase keys
    $request->headers->get('host');
    $request->headers->get('content_type');
}
Request类有几个公开的属性和方法,用来返回你需要的request任意信息.
Response的使用
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;


// create a simple Response with a 200 status code (the default)
$response = new Response('Hello '.$name, Response::HTTP_OK);


// create a CSS-response with a 200 status code
$response = new Response('<style> ... </style>');
$response->headers->set('Content-Type', 'text/css');


JSON Helper
从控制器返回一个json数据,使用json()方法,返回一个特殊的JsonResponse对象,自动进行数据编码.
public function indexAction()
{
    // returns '{"username":"jane.doe"}' and sets the proper Content-Type header
    return $this->json(array('username' => 'jane.doe'));


    // the shortcut defines three optional arguments
    // return $this->json($data, $status = 200, $headers = array(), $context = array());
}


模版
创建和使用模板
一个模板就是一个简单的文本文件,可以生成任意的基于文本形式的格式(HTML,XML,CSV,LaTeX...).最熟悉的模板
类型是php模板,一个被php解析的文本文件,包含了文本和php代码的混合.
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1><?php echo $page_title ?></h1>


        <ul id="navigation">
            <?php foreach ($navigation as $item): ?>
                <li>
                    <a href="<?php echo $item->getHref() ?>">
                        <?php echo $item->getCaption() ?>
                    </a>
                </li>
            <?php endforeach ?>
        </ul>
    </body>
</html>
但是呢,symfony封装了一个非常强大的模板语言,称为twig,twig允许你编写简洁的,可读的模板,对网页设计者是
更加的友好,在几个方面,比php模板更加的强大.
<!DOCTYPE html>
<html>
    <head>
        <title>Welcome to Symfony!</title>
    </head>
    <body>
        <h1>{{ page_title }}</h1>


        <ul id="navigation">
            {% for item in navigation %}
                <li><a href="{{ item.href }}">{{ item.caption }}</a></li>
            {% endfor %}
        </ul>
    </body>
</html>
twig定义了三个特别的语法类型:
{{ ... }}
打印一个变量或者表达式的结果到模板中.
{% ... %}
"做一些事情":一个控制模板逻辑的标签;被用于执行类似for-loops的语句.
{# ... #}
注释.等同于php的/**/语法.被用于添加单行或者多行语句.语句内容不包含在渲染页面中.


twig也包含了过滤器,在渲染之前修改内容.下面的例子,是title变量在渲染之前,变成大写
{{ title|upper }}


twig带有很多的标签,过滤和方法.你甚至可以添加自定义的过滤器,方法或者更多.


twig代码看上去和php代码非常相似,带着点微妙的,nice的差别.接下来的例子,使用了一个标准的
for标签和一个cycle方法去打印10个div标签,交替odd,even类:
{% for i in 0..10 %}
    <div class="{{ cycle(['odd', 'even'], i) }}">
    </div>
{% endfor %}


为什么使用twig?
twig模板意味着简单并且不去操作php标签.这个设计源于:twig模板系统旨在专门的演示,没有程序逻辑.
你越多的使用twig,你将更加欣赏和从他的差别中收益.当然了,无论你在哪儿,你将被网络设计者喜欢.
twig也可以做一些php不能做的事情,例如:空白对照,沙盒,自动html转义,手动上下文输出转义,和自定义
函数和过滤器,这些都只是影响模板的操作.twig包含了是编写模板更加简单更加简洁的特点.下面的例子,
结合了一个带有if语句的循环:
<ul>
    {% for user in users if user.active %}
    <li>{{ user.username }}</li>
    {% else %}
    <li>No users found</li>
    {% endfor %}
</ul>


twig模板缓存
twig快是因为没一个模板被编译成一个纯的php类并且被缓存.但是不要担心:这是自动发生的,不需要你做任何事情,
当你正在开发的时候,twig是足够聪明的,当你做了任何改动之后,会去再编译你的模板.这就意味着twig在开发中是
非常快的,而且在开发的时候是非常简单使用的.


模板继承和布局
往往,模块在项目中共享一些相同的元素,向header,footer,sidebar等等.
在symfony中,这个问题有了不同的考虑:一个模板可以被另一个修饰.这个工作恰恰类似于php类:
模块集成允许你搭建一个基础的"layout"模板,包含了所有的正常的元素.
一个子模板可以集成一个基础的layout和重写任何一个父模板的块.
首先搭建一个基础的layout文件:
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Test Application{% endblock %}</title>
    </head>
    <body>
        <div id="sidebar">
            {% block sidebar %}
                <ul>
                    <li><a href="/">Home</a></li>
                    <li><a href="/blog">Blog</a></li>
                </ul>
            {% endblock %}
        </div>


        <div id="content">
            {% block body %}{% endblock %}
        </div>
    </body>
</html>
这个模板定义了基础的html骨架文档.在这个例子中,有三个{% block %}块.每一个块可以被子模板重写,
或者丢弃默认的实现.这个模板也可以直接的被渲染.在这个例子中,title,sliebar和body块可以简单
的保持默认的值.
一个子模块:
{# app/Resources/views/blog/index.html.twig #}
{% extends 'base.html.twig' %}


{% block title %}My cool blog posts{% endblock %}


{% block body %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
{% endblock %}
模板继承的关键是{% extends %}标签.他告诉模板引擎去找到基础的模板.子模板渲染,被重写的块将
被使用,没有重写的仍然使用父模块的默认值.


使用模板继承的时候,有几点要注意的:
(1)如果你使用了{% extends %},它必须出现在模板中的第一行
(2)更多的{% block %}标签的使用,非常好,记住,子模块不用定义全部的父块,因此可以创建你所想的
尽可能多的块在你的基础模板中,并且给没一个块一个明智的默认值.
(3)如果你发现自己要复制模板的大量内容,那么就意味着,你需要把这段内容移动到父模板的{% block %}
中,在某些情况里,一个更好的解决方法就是,把这段内容移动到一个新的模板中,然后include它.
(4)如果你想从父模板中获取内容,你可以使用{{ parent() }}.当你想把父块中的内容添加到子模块中的,而不是
重写它的时候,是非常有用的.





































































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值