第四天 - 不要害怕完整的应用程序

img

关于Mojolicious最常见的误解之一是,我们目前看到的声明式“Lite”应用程序与大型结构化“完整”应用程序之间存在很大差异。没有东西会离事实很远。 Mojolicious::Lite 是一个非常小的包装器,围绕着所谓的“完整”应用程序架构,赋予它平易近人的关键字语法。

因为文档的简洁单文件示例要好得多,所以 Mojolicious 的大多数文档大多数时候都使用Lite语法。可以理解的是,即使一旦他们的应用程序受益于面向对象的结构,人们也会担心迁移(或者我们称之为“成长”);毕竟所有的文档似乎都面向Lite应用程序。但是,让这些担忧消失,过渡很容易。一旦你理解了它,文档化的例子就很难翻译了。

此外,Mojolicious 在转换时提供两种形式的帮助。第一个是成长指南,涵盖了这篇文章的所有内容,但是从移植现有应用程序的角度来看(我不会在这里复制)。第二个是 inflate 命令,它甚至可以通过将模板从数据部分移动到自己的文件中来启动您的过程。

也就是说,为了进一步揭开神秘面纱的神秘面纱,我将介绍一些差异,并对Lite语法本身拉开帷幕。

让我说服你

在反复试图说服人们两者之间几乎没有什么区别后,我发现有一种非常好的方式来转变对话。我告诉他们代码。没有真正看一看。在撰写本文时,Mojolicious::Lite 只有37行代码(由David A. Wheeler的 SLOCCount计算的)! 37 行代码有多大差异?

好了,现在你相信我,让我们谈谈这些差异。

脚本和类

在 Lite 脚本中,您的应用程序逻辑就位于脚本中。如果是一个完整的应用程序,你的逻辑进入一个单独的类,主要是在 startup 方法中,但删除 app->start 这一行。虽然方法(调用者)的第一个参数通常被称为 $self,你会看到,为了在本系列中保持清晰,我将始终使用 $app。所以我们有:

1
2
3
4
sub startup {
my $app = shift;
... # the rest of what was your script
}

与此同时,运行的脚本只是启动应用程序的几行。该脚本始终是相同的,与您的应用程序无关,而是要调用的类的名称。我只是使用成长指南末尾的那个。

关键词

现在代码生活在正确的位置,它需要被转换为面向对象。第一步是将逻辑放入一个名为 startup 的方法中,该方法将应用程序对象作为其第一个参数。

实际上有三种类型的关键字,即应用程序对象或应用程序上的方法,路由上的方法和 group

app 关键字就是之前的调用,因此 app 成为 $app。关键字 helperhookplugin 只是 app 上的方法,所以 plugin ... 变成 $app->plugin(...) 等。

路由方法有:

  • any
  • del (as delete)
  • get
  • options
  • patch
  • post
  • put
  • websocket

路径对象的方法与之前完全一样。要获取顶级路由对象,请调用 $app-> routes;按照惯例,我们称之为toplevel route object $r

1
get '/' => sub { ... } => 'route_name';

变成:

1
2
3
my $r = $app->routes;
$r->get('/' => sub { ... } => 'route_name');
... # add more toplevel routes to $r

这就是我们所说的“混合路由”。它们基本上使用 Lite 参数,但是给出了方法。当您深入了解 Mojolicious 时,您可能更喜欢通过属性设置路由而不是位置参数

1
$r->get('/')->to(cb => sub { ... })->name('route_name');

但无论哪种方式都有效,请选择您喜欢的方式! TIMTOWTDI再次。

如果您只使用了上述关键字,请按照我刚刚向您展示的方式进行翻译,然后您就完成了。

嵌套路由

到现在为止,你必须看到我一直认为我的陈述是“顶级路由”。好的,所以Lite和Full之间存在一个小的区别,不同之处在于嵌套路由的工作方式。

还有另外两个关键字,undergroupunder 允许路由共享代码,比如说用于身份验证。他们也可以分享他们的部分路径。例如,需要身份验证的API部分可能都在 /protected 下。

1
2
3
4
5
6
7
8
get '/unsafe' => 'unsafe';

under '/protected' => sub {
# check authentication
};

# /protected/safe
get '/safe' => 'safe';

在Lite应用程序中,这些受保护的路由实际上属于它们的 under 下。这种方法很好,直到你认为“现在等待,这意味着我无法回到无保护的空间。”好眼力!那就是 group 进来的地方。

1
2
3
4
5
6
7
8
9
10
11
12
get '/unsafe' => 'unsafe';

group {
under '/protected' => sub {
# check authentication
};

# /protected/safe
get '/safe' => 'safe';
};

get '/another_unsafe' => ...;

等等,什么?

如果你感到困惑,那没关系。我会告诉你一个小秘密,我觉得这也很混乱。嵌套路由的Lite形式实际上更完整,一旦你需要它,它可能是一个好的迹象,你应该看看切换到完整的应用程序。完整的应用程序让它更容易!

在完整应用程序中,路由方法都返回一个新的路由对象。如果将它们存储在变量中,则可以使用它们相互构建。在我看来,这是用于构建嵌套结构的更自然的API。

1
2
3
4
5
6
7
8
9
10
11
my $r = $app->routes;
$r->get('/unsafe' => 'unsafe');

my $protected = $r->under('/protected' => sub {
# check authentication
});

# /protected/safe
$protected->get('/safe' => 'safe');

$r->get('/another_unsafe' => ...);

由于Lite app关键字没有办法附加到另一条路由,因此它们基本上总是将它们添加到“当前全局路由”。这就是混乱的来源。

说到这,我会让你更深入地了解我的秘密。我喜欢链接类型的路由,而不是使用我在Lite应用程序中实际使用它的 group。当然我仍然使用 appplugin,但我做的第一件事就是我的 $r = app->routes。然后,除了最简单的情况之外,我使用它而不是路由关键字。

结论

就是这样,除了使用嵌套路由组,它只是直接翻译。如果你总是使用方法形式的路由,你甚至不用担心!有了这个,我鼓励你回过头来阅读教程和指南,并意识到看起来像Lite应用程序的所有东西都是完全正确的。