10 分钟阅读时间 (1995 个单词)

使用 Joomla 框架开发 JSON API

Developing JSON API with Joomla Framework

在 2013 年底,我被要求开发一个创建交互式计算器的网络应用程序,名为 Calculoid。这对我来说就像一个在糖果店的孩子一样令人兴奋,首先是因为我可以为这个项目选择技术,其次是因为就在同一周,崭新的 Joomla 框架发布了。我决定将应用程序作为单页应用程序(SPA)来开发,客户端使用 AngularJS,而服务器端我决定使用,你可能猜到了,Joomla 框架。

客户端 - AngularJS

单页应用程序的工作方式与大多数 Joomla 用户和开发者所习惯的不同。它根本不会刷新页面。URL 也不会改变。嗯,hash(#)之后的部分会变。快速示例

http://some-domain.com/#/the-part-which-can-be-changed-by-JS

大部分的业务逻辑都发生在客户端的浏览器中。AngularJS 使得处理 hash 路由以及模板系统、自定义指令、服务、ajax 请求等变得更加愉快。它使用与 MooTools 或 jQuery 完全不同的逻辑,当你习惯了它,它确实很有道理。我建议每个人都试一试。

服务器端 - Joomla 框架

服务器在 AngularJS 应用请求时提供数据。服务器不会返回整个 HTML 文档,而是只返回页面中更改的数据,以 JSON 格式。我将在下面更详细地描述客户端-服务器通信。除了提供数据外,服务器还负责用户权限。

JSON REST API

客户端和服务器通过异步 HTTP 请求进行通信。由于 AngularJS 的双向绑定功能和高级模板系统,生成客户端浏览器内的 HTML 非常容易。因此,客户端和服务器之间的通信使用 JSON 格式。JSON 对于 PHP 和 JS 都很容易处理。然后请求就没有额外的 HTML 标签和未更改的页面部分,因此请求更轻量。

想想看。例如:页脚、菜单、标志。在大多数网站上,这些元素在每一页都是相同的,但它们是随着每个HTTP请求生成和发送的。在单页应用(SPA)中,它只需加载一次,如有需要再进行修改。这样可以节省大量的带宽、能源和时间。

如果你正在考虑创建一个带有JSON REST API的Web应用,不妨试试apiary.io。这是一个用于API设计和测试的工具。

Joomla框架(JF)经验

最后,当我们知道JF的使用目的后,让我们谈谈我在开发JSON REST API服务器过程中获得的经验。

入门

与JF入门并不像我想象的那么容易。我从GitHub上拉取了JF,然后我就迷失了方向。新的库很棒,但如何开始呢?幸运的是,我在GitHub上找到了David Hurley提供的JF示例应用,这让我受益匪浅。我可以看到应用程序的结构应该是什么样的,以及如何将各个部分连接起来。现在,David的应用链接已经位于JF网站首页,所以你不应该错过它。

让我们看看JF和David的示例应用中的几个对我来说完全陌生的功能。

路由器

我非常喜欢David在他的示例应用中使用路由器的方式。这并不是JF强制你实现的方式,而只是实现它的一种方法。我经常对Joomla CMS的路由器工作方式感到困惑。它非常复杂,以至于让我多次噩梦连连。无论如何,看看David的路由器

https://github.com/dbhurley/framework-app/blob/master/App/Config/routes.json

这是一个简单的JSON文件,你可以在其中定义所有需要的URI类型以及应该处理请求的控制器。它很简单,但又不愚蠢。仔细看看

"news/:task/:id": "\\Controller\\NewsController"

:task和:id是HTTP请求变量的一部分,当你需要它们时。这些URI是等价的

/news/save/33 /news?task=save&id=33

命名空间

JF是一个前沿的PHP框架,它使用Composer的自动加载,这非常酷。我根本不需要包含或要求任何PHP文件。好吧,有必要将自动加载器包含在index.php中,但David在我的示例应用中为我做了这件事,我用它作为我应用程序的基础。

Joomla CMS通过J前缀解决了类名问题。所以,Date类在Joomla CMS中是JDate类。命名空间允许JF有正常的类名,而不用担心与其他名为Date的类发生冲突。

如果你不熟悉命名空间,请查看以下模型的开始几行,以查看现场示例

https://github.com/dbhurley/framework-app/blob/master/App/Model/NewsModel.php

一个类可以这样分配给一个命名空间

namespace App\Model;

class NewsModel { … } 

这意味着NewsModel类可以在App\Model命名空间(文件夹)中访问。使用命名空间的主要原因是可以存在相同的NewsModel类在App2\Model命名空间中。你可以通过指定哪些命名空间应被加载到文件(例如视图)中,来决定使用哪一个

use App\Model\NewsModel; 

当与其他库一起使用JF时,使用命名空间是一个非常好的主意。而且你会的,因为Composer的使用非常简单。有两个PHP类具有相同名称的可能性相当高。

使用命名空间是迷人的。如果你指定了如上例所示的命名空间,你只能使用App\Model命名空间(文件夹)中的NewsModel。如果你更模糊地指定

use App\Model;

然后您可以使用App/Model命名空间下的所有模型。当我提到“使用模型”时,我的意思是这样创建一个新的实例

$newsModel = new NewsModel;

您也可以在不指定类文件顶部的情况下使用NewsModel,但这时您必须使用完整的命名空间路径来创建新对象

$newsModel = new \App\Model\NewsModel;

在我看来,这并不是很整洁,所以我建议在类之前定义所有使用的命名空间。

在一个文件中,您也可以使用相同名称的2个类而不会出错,当您使用这样的别名时:

use Joomla\Date as JDate;

use App\Date;

还有一件事情我应该提到以节省您一些调试时间。PHP通用类不会像您习惯的那样工作。例如

$emptyObject = new stdClass; // 抛出错误

因为您没有指定命名空间。这是正确的方式来做

$emptyObject = new \stdClass; // 一切都很顺利 

依赖注入(DI)

作为一名Joomla扩展开发者,我非常习惯使用JFactory::something()这样的静态方法,我可以从任何我想要的文件中调用它。它非常容易使用,但从软件架构的角度来看,它不是一个好的设计。主要是因为具有静态类/方法的代码很难测试。它也不被认为是一个好的面向对象实践。

尽管我认为我在我的应用中并没有完全按照书本来做,但我将尝试解释它,这样您就会明白了。让我们以我们的NewsModel为例。新闻有一个作者。当没有jFactory::getUser()时,我们如何在保存新闻时加载当前作者/用户?我想到了几个选项。

A) 在需要的地方创建一个新的User实例。

namespace App\Models

use App\Helpers\User

class NewsModel

{

   public function save()

   }

       $user = new User();

       $user->loadCurrentUser();

       // ...

   }

}

这可能不是最优的方法,因为它可能会从不同的位置多次加载当前用户,而User类的每个实例在某一时刻都可能处于不同的状态,这可能会有些令人困惑。

B) 在构造函数中创建新的User。

namespace App\Models

use App\Helpers\User

class NewsModel

{

   protected $user;

   public function __construct()

   {

       $this->user = new User();

   } 

   public function save()

   }

       $this->user->loadCurrentUser();

       // ...

   }

}

这更好,因为NewsModel的所有方法只有一个User类的实例。我假设loadCurrentUser是一个智能方法,它不会像被调用那么多次从数据库中加载用户,而是一次加载并记住它。但是等等,我可能需要在其他类中也要使用User。所以我回到了之前的位置。

C) 为整个应用全局创建一个新的User,并将其注入到依赖于它的对象中。嘿,那听起来就像依赖注入。

namespace App\Models

use App\Helpers\User 

class NewsModel

{

   protected $user;

   public function __construct(User $user)

   {

       $this->user = $user;

   }

   public function save()

   }

       $this->user->loadCurrentUser();

       // ...

   }

}

就是这样!DI并不像您想象的那么困难。注意,我已经指定了构造函数的参数是User的类型。猜猜如果有人用不同类型的参数创建新的NewsModel会发生什么

$newsModel = new NewsModel('John Doe');

是的,您猜对了

“可捕获的致命错误:传递给NewsModel::__construct()的参数1必须是User的实例,字符串给出,调用在……中定义在……中”

这是我见过的PHP中最详细的错误描述。这不是很美吗?

D) DI容器

您可以将一步更进一步,使用JF的依赖注入容器。这基本上是一个类,您可以将最常用的对象(数据库对象、配置对象、用户对象等)注入其中,然后将这个依赖注入容器作为NewsModel的依赖项注入。我认为DI容器可以类比为JFactory类。

文档

文档是每个(新)项目的薄弱环节。谁愿意花时间在文档上,而不是开发新功能呢?但是JF的开发者们做得非常出色。让我给你讲一个例子,那是我在遇到缺失文档问题时的情况。

我想让我应用的用户使用他们的Google账户进行身份验证。

1. 选项 - Google

搜索“joomla framework google oauth 2”。即使现在,距离JF发布已有6个月,你仍然可以找到关于如何使用JF与Google oauth 2配合使用的问题的答案。这对于这样一个新的项目来说真是令人惊讶。在我需要的时候,什么都没有。

我在布拉格的Joomla Day上看到,许多与会者对这个名称感到困惑。“嗯,Joomla Framework。这不就是Joomla平台的前身吗?”好吧,不仅人们感到困惑,连谷歌也是如此。所以当你搜索Joomla Framework时,你会得到很多无关的结果。

2. 选项 - GitHub Readme

我发现每个包都有自己的文档,位于GitHub代码下方。看看JF的Google API包

https://github.com/joomla-framework/google-api

正如你所看到的,它有很好的描述和示例。遗憾的是,在撰写本文时,缺少了如何使用该包中包含的Google Oauth2。

3. 选项 - 测试

如果你找不到使用所需代码的示例,请转到“测试”文件夹并查找它。JF有很好的测试覆盖。测试 = 使用示例。请自己看看

https://github.com/joomla-framework/google-api/blob/master/Tests/JGoogleAuthOauth2Test.php#L59

4. 选项 - Composer

如果你真的无法让JF的一部分为你工作,那么就使用你熟悉的任何其他库。这就是JF最棒的部分,你不需要用它来处理所有事情。它甚至鼓励你这样做。这就是为什么JF被划分为小型的独立包。你可以从不同的库中选择每个包。这就是我所称的自由。

以Google oauth 2为例,我使用了由谷歌直接提供的详细描述的库(https://developers.google.com/api-client-library/php)。

结论

你今天想使用最新的技术吗?你想学习如何编写更好的OOP代码吗?你想在应用程序的每个部分使用什么都有自由吗?如果你对这些问题的回答是“当然”,那么你还在等什么?Joomla Framework正是你所需要的!

发表在Joomla社区杂志上的某些文章代表作者对特定主题的个人观点或经验,可能不代表Joomla项目的官方立场。

0
Joomla! 3 - 适合每个人的书
 

评论

已注册? 在此登录
尚未发表评论。成为第一个发表评论的人

通过接受,您将访问 https://magazine.joomla.net.cn/ 以外第三方提供的服务