Laravel 开发框架的控制器函数通常都是绑定到路由,然后以 HTTP 请求方式来调用。因为一个小小的想法作祟,我准备尝试一下在命令中直接调用控制器函数,结果比预想中要简单。
让我产生此想法的需求来自静态缓存功能。比较通用的静态缓存方案一般都是被动方式,比如访问者首次浏览页面时自动生成。而我想的是对于某些比较慢的页面,如果提前生成缓存页面,是不是能够「些微」提升一点用户的首次访问体验?所以我想实现这么一个主动缓存的功能。
在 Laravel 框架的命令中调用其他命令可以用 $this->call
方法,在控制器函数中调用命令可以用 Artisan::call
方法。但没有为命令中调用控制器函数提供任何便利的途径。也许这本身就是一个很小众,或者说是可有可无的需求吧。不过好在 Laravel 框架低耦合的设计模式让这件事做起来并不复杂。
无参数的控制器函数
无参数的控制器函数调用起来最简单,首先来看看这种。下面是我在命令中调用首页控制器函数的主要代码:
use App\Http\Controllers\HomeController;
public function handle()
{
$view = (new HomeController)->index();
$html = $view->render();
}
HomeController
是我的首页控制器,index
是处理首页业务逻辑的视图函数。通过直接实例化控制器对象,并调用 index
方法,可以得到一个 Illuminate\View\View
实例化对象。调用它的 render
方法能获取到模板渲染后的纯 HTML 代码,可以直接拿来作为缓存内容。
有参数的控制器函数
有参数的控制器函数调用起来会稍微麻烦一点。以我的文章详情页控制器函数为例:
/**
* 文章详情
*/
public function show(Request $request, $slug)
{
// ...
}
它有两个必要的参数:$request
和 $slug
。前者是 Laravel 的请求对象,后者是定位文章的传参。调用这个函数前需要先准备好这两个参数。
use App\Http\Controllers\PostController;
use Illuminate\Http\Request;
public function handle()
{
$request = new Request();
$view = (new PostController)->show($request, 'about');
$result = $view->render();
}
如果有更复杂的传参,可以在 new Request
对象时提供。它继承自 Symfony\Component\HttpFoundation\Request
对象,在实例化时可用的参数请参考如下源码:
/**
* @param array $query The GET parameters
* @param array $request The POST parameters
* @param array $attributes The request attributes
* parameters parsed from the PATH_INFO, ...
* @param array $cookies The COOKIE parameters
* @param array $files The FILES parameters
* @param array $server The SERVER parameters
* @param string|resource|null $content The raw body data
*/
public function __construct(
array $query = [],
array $request = [],
array $attributes = [],
array $cookies = [],
array $files = [],
array $server = [],
$content = null
)
{
// ...
}
一点点想法
虽然目前我只是想尝试一下主动缓存,不过这个功能延伸一下,也可以做点有意思的项目,比如带后台的「静态站点」引擎。想想可比那些依赖终端命令的纯静态站点引擎有意思多了。