Symfony 框架实战教程——Symfony 5 极简教程

Symfony 框架实战教程——Symfony 5 极简教程

Chris Yue 4 comments
Posts

我最近注意到一个事情:无论是网页浏览统计的数据还是打赏的数据,都显示我这破网站基本没啥人访问,但除了 Symfony 相关的一些教程,特别是框架实战系列教程。不要看我一直在推 Symfony,实际上我一直觉得在国内用 Symfony 做项目就是一个巨坑,主要问题是中国大陆的 Symfony 开发者实在太少了,光招人就会让人头发掉一半。然而让我感到欣慰的是,Symfony 相关文章的阅读数似乎没有减少并且略微有所增加,让我并没有放弃继续推广 Symfony 框架给大家,另外 Symfony 4/5 的发布,让 Symfony 的使用更加的现代和易用,因此我觉得有必要将之前 Symfony 2.X 时代的教程做一次升级,让大伙儿看看最近的 Symfony 的情况。

废话不多说,让我们开始教程,Here we go~(看得出我最近在 B 站关注谁了吗)

第一天:创建项目

创建项目之前我们需要检查运行环境是否达到 Symfony 5 的要求。到今天也就是 2020-04-12 Symfony 5 框架运行的最低要求是 PHP 7.2.5 且安装了 php-xml 扩展。确认满足需求之后,我们就可以开始初始化 Symfony 项目了。

创建项目的方式有两种,一种同老教程一样,使用 Symfony Installer 安装,不过这一次我不打算使用这种方式,因为 Symfony Installer 会引入很多其他的话题,比如为什么要用 Symfony Installer,用它有什么好处,除了安装 Symfony 项目它还提供什么功能……为了让读者先集中精神,将注意力集中到 Symfony 框架本身,这次我就使用 Composer 的 create-project 命令来初始化框架。

假设项目的路径是 ~/demo,我们需要执行下面的命令使用 Composer 进行项目安装。同样,为了保证篇幅,此教程只说 Symfony 5,如果有读者对 Composer 的安装和使用不熟悉,请自行查询。另外再加一个友情提示:为了让此教程进行得更加『顺心』,建议大家把『如何设置 Composer 镜像』这个问题也先解决一下。

# 在 ~ 目录运行下面命令
composer create-project symfony/skeleton demo
# 或者
composer create-project symfony/website-skeleton demo

上面两个命令选一个即可。它们的区别是,skeleton 只默认安装实现一个 HTTP 应用最基本的库,而 website-skeleton 则默认安装了更多的库,它假设项目要用模板,要用数据库,要实现用户登录……并且还包含一个页面的例子,可以说是『豪华套餐』。如果你两个命令都尝试过,可以发现第二个命令安装的库几乎是第一个的三倍之多。

但为了体现 Symfony 5 的快速与简洁,我推荐使用第一种方式来创建我们的项目,之后我们将按照例子的实际需求来添加需要的其他库。

由于安装的是最简版本,则不会包含示例代码,也没有内置的 Web 服务,所以相对于原教程,第一天的内容就已经结束了,此时可以运行一下 bin/console 命令来确认 Symfony 项目是否安装正常。如果没有问题此命令将会列出 Symfony 提供的所有命令行工具及其用法。

第二天:创建新页面

由于安装的是精简版,我们也无需像原教程一样清理不需要的项目文件,而可以直接创建新控制器和页面。

我们可以直接添加控制器文件来创建页面,不过在 Symfony 5 里有更方便的做法:用 Symfony 的 make 命令来帮我们生成,这样我们就不用写控制器文件了。其实创建文件没有什么不方便,真正麻烦的是文件内容不好记,但有了 make 工具后就不再依赖人类不靠谱的记忆来创建代码文件了,这是最大的好处。

make 命令是由 MakeBundle 提供的,精简版并没有,我们需要添加它:

composer require make

composer 在添加一个新的依赖时,依赖的库名都是 */* 的格式,比如 phpunit/phpunit,但得益于 symfony-flex 这个 composer 扩展,我们可以使用简写,比如这里的 make。有关 flex 介绍,可参考我之前的一篇文章

安装好 MakeBundle 之后,我们可再执行 bin/console 命令列出所有 Symfony 命令行工具,不出意外应该能看到多出了一堆 make 相关的命令。

我们的实例依然同老教程一样,做一个可以发布新闻的网站。

下面我们就用 MakeBundle 来创建 NewsController

bin/console make:controller

然而,执行完上述命令后却收到一个错误信息,不过此此错误并不是什么很严重的错误,它只是很贴心得告诉你,如果想要使用这个命令,你需要安装 doctrine/annotation,甚至连命令都直接显示给你了

[ERROR] Missing package: to use the make:controller command, run:
composer require doctrine/annotations

按提示安装好 doctrine/annotations 库后,再次运行 make:controller 命令,这时命令会问你,控制器的名字叫什么,我们输入 NewsController 并回车,提示创建成功后,我们便可以在 src/Controller 目录下看到新生成的 NewsController.php 文件了。

并且这个控制器也是可以访问的了。我们打开 PHP 内置服务器,并指定 public 为根目录:

php -S localhost:8000 -t public

浏览器访问 http://localhost:8000/news ,我们便可以看到以 json 形式返回的内容了

到这里第二天的内容也结束,是不是感觉 Symfony 5 让开发变得更快了?

第三天:实现列表和翻页

我们的新闻内容将存放在数据库里,包含标题和正文。为了让我们的应用与数据库交互,我们需要 Doctrine 这个 ORM 库来实现,另外我们应当先确保是否安装了 PHP 的 pdo-mysql 扩展,这里就假设大家都已经安装了。

在老教程中,我们使用 doctrine:generate:entity 命令来生成实体以及相关 CRUD 操作页面,现在生成代码的命令被统一放在了 MakeBundle 里,原来生成 CRUD 的命令现在叫 make:crud。因为这个命令也会自动创建控制器,并且包含了操作实体的代码,我们先把第二天用来演示的 NewsController.php 文件删掉。

尝试使用以下命令来生成一个 ORM 对象,以及相关的控制器和模板等文件:

bin/console make:crud

这一次 MakeBundle 依然会友好得告诉你,要使用这个命令你需要安装若干的依赖。我们按命令给的提示,将这些依赖安装好了之后,再次运行 make:crud 命令,会提示让我们提供 ORM 类的类名。我们输入 News 后回车,会被告知并没有 News 这个实体类。这是 make:crud 命令与 doctrine:generate:entity 不同的地方,make:crud 要求先有实体类,再根据实体类生成相关的文件。而生成实体类文件,也是可以通过 make 命令实现的:

bin/console make:entity

根据命令行的提示,输入实体类的类名 News,第一个字段名 title,字段类型 string,字段长度 255,是否可为 null no,第二个字段名 body,字段类型 text,是否可为 null no,最后问你是否还要添加其他字段的时候直接回车,提示成功后可以发现 src 目录下多了 Entity/News.phpRepository/NewsRepository.php 两个文件。

这时,我们再执行 make:crud 命令,提示输入实体类名时输入 News 就不会报错了,并且生成了一堆文件。另外还友好得提醒你可以通过访问 /news/ 查看。当然我们现在肯定是不能正常查看的,毕竟我们数据库都还没启动呢,另外我们还需要设置访问数据库的相关配置。

我们先开启本地的 MySQL 服务,然后打开项目根目录下的 .env 文件,最后一行是链接数据库的配置,应当不用我多说大家看此文件提供的例子也应该知道怎么改成自己的配置。

配置完成之后,我们还应当生成数据库和表。这跟以前 Symfony 版本的命令是一样的:

# 先
bin/console doctrine:database:create
# 生成数据库,再
bin/console doctrine:schema:create
# 生成表

小提示:Symfony 的命令行工具都是可以简写的,比如 doctrine:database:create 可以写成 doc:data:cre,甚至 d:d:c,只要不会和其他的命令产生冲突就能执行。

此时我们就可以访问 /news/ 路径了,并且可以通过页面添加、查看、更新、删除数据。

接下来我们再来处理分页的需求。同以前一样,我们需要通过 Composer 来安装第三方库实现分页:

composer require knplabs/knp-paginator-bundle

从这也能看出来,不是所有的库都能用缩写,关键看库有没有被 Symfony flex 『收录』。

接下来我们修改现有的代码来使用分页。似乎到这里我们才第一次写代码……首先我们修改 NewsController.php 文件:

<?php

namespace App\Controller;

...
use Knp\Component\Pager\PaginatorInterface;

/**
 * @Route("/news")
 */
class NewsController extends AbstractController
{
    /**
     * @Route("/", name="news_index", methods={"GET"})
     */
    public function index(NewsRepository $newsRepository, PaginatorInterface $paginator, Request $request): Response
    {
        $qb = $newsRepository->createQueryBuilder('n');

        return $this->render('news/index.html.twig', [
            'pagination' => $paginator->paginate($qb, $request->query->getInt('page', 1), 5 /* 一页 5 条*/),
        ]);
    }

    ...
}

值得一提的是,得益于 Symfony 3 开始的 autowire 技术,我们所需要的服务可以直接通过添加方法参数的方式来指定了,比如上面例子中的 $paginator$request 参数,对比以前的写法,是不是又精简好多?

另外,templates/news/index.html.twig 文件也需要得到相应的修改:

...
    <table>
        ...
        <tbody>
        {% for news in pagination %}
            <tr>
                ...
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <nav>
        {{ knp_pagination_render(pagination) }}
    </nav>
...

大家可以多添加几条新闻数据试试翻页效果。

到此第三天内容结束。

第四天:用户注册和登录

老教程的第四天有两章,这里为了控制篇幅就只介绍其中的一章,保留更常见的注册 + 表单登录,抛弃了 OAuth2.0 登录。

老教程介绍注册登录时,使用了一个第三方库辅助实现,但为了体现 Symfony 5 的特点,本章不再用任何第三方库,而是直接实现。

既然是用户注册和登录,那么我们首先得有用户实体,通过 make:user 命令可以帮我们创建这个实体:

bin/console make:user

直接运行此命令会提示我们安装『安全』组件,安全组件是用来做用户登录和检查用户登录状态和权限的。我们按提示安装好 security 库之后,再一次执行 make:user 命令,根据命令提示,用户类名我们输入 User,是否使用数据库存储用户,输入 yes,用于显示用户的字段,选 username,用户密码是否需要加密?输入 yes,最后命令会生成 src/Entity/User.phpsrc/Repository/UserRepository.php 文件,并且还会自动更新安全相关的配置 config/packages/security.yaml

我们还需要再一次执行 bin/console doctrine:schema:update --force 命令,将 user 表在数据库里创建出来。

接下来,执行下面的命令来生成用户登录逻辑相关代码:

bin/console make:auth

看来该依赖的库都安装完毕,终于可以一次性执行 make 命令了。根据命令提示,选择什么风格的认证方式,这里选择 1,即表单登录风格;身份验证类的类名,叫啥都行,我输入的是 FormLoginAuthenticator;登录时用的控制器类名,直接回车使用默认的 SecurityController;是否生成『退出登录』的链接,选择 yes。然后又生成一堆文件,还提示你要将生成好的身份确认类文件里的 TODO 按实际业务需求做相应的修改,比如登录成功了要干嘛,这里我们先不管它。

最后,执行下面命令生成用户注册表单:

bin/console make:registration-form

然后又是一堆问题:是否检查重复用户名,那肯定是 yes;注册成功后是否自动登录,这里我选 yes,然后又是生成一堆文件,并且还提示你『请前往路径 /register 查看注册页面』。到目前为止,依然是一行代码没写,仅靠无情的代码生成机器 MakeBundle,我们就已经把注册搞定了。

尝试注册一个用户,如果成功注册,页面会报错,并提示说在 FormLoginAuthenticator.php 文件有需要修改的地方,即指定登录成功后要做的事情,也就是之前执行的命令运行完后让我们修改 TODO 的那个地方。实际上此文件相关位置已经写好了示例代码,如果登录成功则跳转到某个页面上去,我们采纳这个方案,将代码的注释去掉,然后将跳转的路由名改成我们创建的『新闻首页』的路由名 news_index 即可:

<?php

namespace App\Security;

use ...

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
    ...

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        ...

        return new RedirectResponse($this->urlGenerator->generate('news_index'));
    }

    ...
}

在老教程里,看一个用户有没有登录,可以通过超级好用的 Symfony 调试工具栏来观察。我们安装的精简版默认没有安装它,但通过下面命令也可以轻松装上:

composer req profiler --dev

注意我们安装调试工具栏只是为了在开发的时候使用,所以上面命令最后的 --dev 指定了只安装在开发环境。

另外还有一个小提示,注意现在 composer 的 require 命令也可以简写为 req 了。

安装成功后,刷新页面,熟悉的调试工具条又回来了。

还记得之前我们指定了退出登录的链接 /logout 吧?我们先直接访问它退出登录状态,然后访问一下创建文章的页面,依然是可以访问的,因为我们还并没有告诉 Symfony 框架,创建文章是需要登录的。跟老教程一样,我们需要在 config/packages/security.yaml 里做一些配置:

security:
    ...
    access_control:
        - { path: ^/news/(new|(\d+\/edit)), roles: IS_AUTHENTICATED_FULLY }

再次刷新页面,就会跳转到登录页 /login 让用户登录了。输入正确的用户名密码会自动跳转回创建新闻页。实际上上面的配置不仅让创建新闻需要登录,编辑新闻也需要登录。

到此第四天的教程已经结束。

原教程实际上还有第五天和第六天两章,不过因为无法体现 Symfony 5 的优点,我觉得就没必要再重新写一遍了(好吧,主要是因为懒……)。

如果你是从老教材过来的,不知道有没有注意到一个细节,Symfony 5 (包括 4 )安装 bundle 之后,都没有将 bundle 开启这个步骤了。其实不是没有开启 bundle,这个步骤依然存在,只是 Symfony 帮你做了,这也是 Symfony 4/5 一个很大的改进。另外大家观察现在的配置文件,基本上都是一个 bundle 对应了一个配置文件,相较于原来 Symfony 2/3 的一个配置文件管所有的方式,分开放不但维护更容易,而且还有一个特别大的好处:当你删除某个 bundle 的时候,一个 bundle 一个配置文件的方式把删除 bundle 相关配置这个操作变得很容易实现,所以现在 Symfony 在删除某个 bundle 的时候,是会自动删除相关配置文件的(而且也会自动删除开启 bundle 的代码),再也不会出现以前删掉某个 bundle,但因为配置没删干净而导致报错了。

Symfony 4/5 的改进并不限于此,此篇教程仅仅为了带大家看看 Symfony 现在的世界长什么样。说实话,迫于目前的客观环境,我最近也不是经常用 Symfony 了,但依然希望能与更多对 Symfony 这款优秀的框架感兴趣的小伙伴多交流,如果有想加好友的请在评论里留言吧。因为所有的留言都会先审核,大家不用担心自己的联系方式会被暴露,我都会做处理。

Symfony 框架实战教程——Symfony 5 极简教程 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人

4 Comments

mash

九月 24, 2020 在 11:54 上午

评论呢? 需要审核?

mash

九月 24, 2020 在 11:53 上午

我差 我竟然一直用symfony开发公司的项目且都是erp等逻辑交叉比较多的项目, 觉得好亏 嗯 给后来者留的坑估计不好填。 早知道用tp给公司开发项目了 哈哈

orcsor

八月 20, 2020 在 3:49 下午

不用symfony用什么?

    Chris Yue

    八月 20, 2020 在 4:17 下午

    看情况吧。
    如果你是受聘者,那基本没得选,听公司安排就好
    如果你是招聘者,那最好是啥好召人就选啥
    如果你不怕找不到人,就喜欢 Symfony,那就用 Symfony

     

发表评论

30 + = 37