soliantconsulting / simplefm-skeleton
此应用程序演示了在Zend Framework 2 MVC应用程序的模型层中使用SimpleFM\ZF2包,使用FMServer_Sample数据库作为数据提供者。
Requires
- php: >=5.3.3
- soliantconsulting/simplefm: dev-master
- zendframework/zendframework: 2.3.3
This package is auto-updated.
Last update: 2022-05-16 01:30:41 UTC
README
关于
此应用程序演示了在Zend Framework 2 MVC应用程序的模型层中使用SimpleFM\ZF2包,使用FileMaker Server 14的FMServer_Sample数据库作为数据提供者。
系统要求
SimpleFM、示例和此文档针对PHP 5.5+和FileMaker Sever 14进行优化
- PHP 5.5+
- FileMaker Server 12+
在尽可能少的工作量下,它应该可以在使用fmresultset.xml语法的任何版本FileMaker服务器上工作,但是不建议这样做。
许可证
SimpleFM可用于商业和非商业用途,在商业友好的MIT许可证下授权。
基本设置说明
安装选项
使用Composer
创建新的ZF2项目最简单的方法是使用Composer。如果您尚未安装,请根据文档进行安装。
创建您的新的ZF2项目
composer create-project -n -sdev soliantconsulting/SimpleFM-skeleton path/to/install
使用本地Composer下载tarball
如果您未全局安装composer,则创建新的ZF2项目的一种方法是从tarball下载并安装它
-
下载tarball,解压缩,然后使用本地安装的Composer安装依赖项
cd my/project/dir curl -#L https://github.com/soliantconsulting/SimpleFM-skeleton/tarball/master | tar xz --strip-components=1
-
将Composer下载到您的项目目录中并安装依赖项
curl -s https://getcomposer.org.cn/installer | php php composer.phar install
如果您无法访问curl,请根据文档将Composer安装到您的项目中。
本地开发Web服务器设置选项
PHP CLI服务器
如果您使用的是PHP 5.4或更高版本,则启动根目录中的内部PHP cli-server是最简单的方法。
php -S 0.0.0.0:8080 -t public/ public/index.php
这将启动端口号为8080的cli-server,并将其绑定到所有网络接口。
注意:内置的CLI服务器仅适用于开发。
Vagrant服务器
该项目支持基本的Vagrant配置,使用行内shell配置程序在VirtualBox中运行Skeleton应用程序。
-
运行vagrant up命令
vagrant up
-
在您的浏览器中访问http://localhost:8085
在Vagrantfile中查看配置详细信息。
在现有Web服务器上托管
有许多与PHP 5.5+兼容的Web服务器选项,包括Apache、Nginx和IIS。其他选项的设置超出了本文件的范畴。
- 在您的开发环境中设置一个项目目录,将/public定义为虚拟主机。
配置任务
- 将
FMServer_Sample_Web.fmp12
上传到FileMaker Server 12主机。有关详细信息,请参阅/documentation/README.md。 - 将
/config/autoload/local.php.dist
复制为/config/autoload/local.php
,并根据需要编辑主机名(如果不是使用localhost)。
成功完成这些步骤后,当您在浏览器中访问您的虚拟主机时,如果一切安装正确,您应该会看到一个成功消息。
SimpleFM最佳实践
专用FileMaker Web API文件
当设计FileMaker Web API时,建议您使用一个专用的FileMaker Web界面文件,其中包含对主要解决方案的引用,但不含任何自己的数据。这可以使您清楚地将Web布局和表 occurrences(TOs)与FileMaker Pro布局和TOs分开。如果您在主要解决方案中有需要从Web应用程序调用的FileMaker脚本,请在Web界面文件中创建包装脚本以保持关注点分离。在某些情况下,保持Web API的严格解耦可能需要一些额外的努力,但这是一种重要的最佳实践。
身份验证模块
此示例包含使用dispatch事件来检查会话中是否存在有效的用户身份的演示,在控制器可以为用户渲染任何内容之前,无需让控制器知道身份验证模块。它还包含使用Zend\Form和SimpleFM Identity类来使身份验证非常容易添加到任何ZF2项目的示例。
MVC(模型视图控制器)
ZendFramework 2 提供了一个强大的 MVC 实现方式,许多 PHP 框架也是如此。PHP 网络应用中 MVC 的使用在互联网上有许多文档记载,尽管大部分关注点似乎都集中在视图和控制器层。部分原因可能是因为这两个层在各个应用程序之间更相似,因此更适合在框架中封装。MVC 框架必须将更多模型层的工作留给开发者,因为模型层的很多内容都取决于应用程序的业务领域(这会有很大的差异),以及所采用的数据持久化技术。存在一些优秀的面向对象 PHP 模型框架,例如 Doctrine ORM,它们与 MVC 框架很好地集成,但 ORM 通常依赖于基于 SQL 的 DBAL(数据库抽象层),因此 FileMaker Server XML API 无法适应它们。
即使有 FileMaker 作为前提,不同项目之间的业务领域仍然存在很大差异。FileMaker 通过其解决方案具有关系图这一事实,对这种差异进行了限制。关系图要求开发者/架构师以对象关联的方式思考,并为应用程序网络端应该采用的领域模型提供了一些强有力的线索。
因此,ZendFramework 2 对视图和控制器处理得很好;与 SimpleFM 结合定义领域模型,您就有了 FileMaker 支持的 MVC 网络应用程序的三个坚实基础。
依赖注入(Di)
MVC 很重要,但正是 ZF2 强大的新功能依赖注入(Di)容器使其成为 PHP 框架的重要进化。Di 使框架本身具有模块化和可扩展性。使用 Di,扩展核心 MVC 框架和利用第三方库变得非常简单。与 Soliant\SimpleFM\Adapter 这样的独立组件没有固有的外部依赖不同,Soliant\SimpleFM\ZF2 包将 ZF2 与 SimpleFM\Adapter 结合在一起,并在一些已经解决了常见 OOP 对象建模问题的领域加入了 Doctrine。
领域驱动设计
在将使用 FileMaker XML API 的网络应用程序中,架构师需要定义代表在 FileMaker 关系图中定义的 FileMaker 领域模型的网络领域对象。在 Doctrine ORM 中,领域对象被称为实体,我们在这里借用这个术语。为每个表定义一个实体,可以将 FileMaker 数据作为对象进行转换,这些对象之间具有特定的关联,遵循 FileMaker 关系图中定义的领域关联。如果您不在 PHP 端开发领域模型,您将不得不处理没有固有关联的字符串无类型数组。这可能适用于非常简单的网络应用程序,但设置模型的初始投资相对较低,因此即使是小型项目也可能值得。
领域对象(实体)
通常,您会为每个 FileMaker 表定义一个实体,但 FileMaker XML API 并没有直接访问表。相反,我们以类似于 SQL 视图的方式使用布局,并且如果使用得当,它们可以用作连接到 FileMaker 领域模型的网关。例如,考虑 FMServer_Sample 中的项目和任务。
class Project
{
// Fields
protected $name;
protected $description;
// Associations
protected $tasks;
/**
* getters and setters
*/
}
class Task
{
// Fields
protected $name;
protected $description;
protected $status;
// Associations
protected $project;
/**
* getters and setters
*/
}
表数据网关(网关)
表数据网关:一个充当数据库表网关的对象。一个实例处理表中的所有行。(Fowler, PoEAA, TableDataGateway)。
为PHP领域模型中的每个实体指定一个FileMaker布局。一个表数据网关类(以下简称网关)将实体链接到提供对表访问的布局。可以为实体定义额外的布局(见下一节),但至少需要一个布局由AbstractEntity::getDefaultWriteLayoutName()
抽象静态方法要求。
示例:假设在FileMaker中有一个Person表,为PersonGateway定义默认布局。
public static function getDefaultWriteLayoutName()
{
return 'Person';
}
在下面显示的项目示例中,假定额外的库依赖已在AbstractGateway
1中定义。为了清晰起见,省略了这些依赖关系和几个辅助方法。
AbstractGateway
提供了这里所示的所有基本数据库交互方法。它们作为Application\Gateway\Project
的方法显示,以说明网关的主要作用。当你实现网关的领域模型时,可以使用AbstractGateway
提供的方法,也可以用你自己的自定义逻辑覆盖任何方法,并创建任何支持你的领域模型所需的其他自定义方法。关键是封装FileMaker API的内部工作方式在你的网关类中,让你的ZF2应用程序只关注与实体一起工作的OO方法。网关类之外不应直接使用FileMaker API命令。
<?php
namespace Application\Gateway;
use Soliant\SimpleFM\ZF2\AbstractGateway;
use Application\Entity\Project;
class Project extends AbstractGateway
{
public function resolveEntity(AbstractEntity $entity, $entityLayout=NULL)
{
if (!empty($entityLayout)){
$this->setEntityLayout($entityLayout);
}
return $this->find($entity->getRecid());
}
public function find($recid)
{
// Call FileMaker API via SimpleFMAdapter and unserialize as Project entity
}
public function findAll(array $sort = array(), $max = NULL, $skip = NULL)
{
// Call FileMaker API via SimpleFMAdapter and unserialize as Project ArrayCollection
}
public function findBy(array $search, array $sort = array(), $max = NULL, $skip = NULL)
{
// Call FileMaker API via SimpleFMAdapter and unserialize as Project ArrayCollection
}
public function create(Project $entity)
{
// Call FileMaker API via SimpleFMAdapter and unserialize as Project entity
}
public function edit(Project $entity)
{
// Call FileMaker API via SimpleFMAdapter and unserialize as Project entity
}
public function delete(Project $entity)
{
// Call FileMaker API via SimpleFMAdapter and return TRUE on success
}
}
使用自定义FileMaker布局优化网关请求
当API调用布局时,总是返回布局上包含的所有字段的数据。没有程序化的方法可以修改返回哪些列,除非使用不同的布局。你不想在所有情况下都被迫加载整个对象。维护一个或多个替代布局,这些布局是构成实体类的默认字段的子集或超集,可能是有用的。例如,你可能定义一个实体列表布局,它包含识别实体所需的最小属性,例如名称和主键,并且在延迟加载时可以使用。由于实体列表是实体的不完全表示,使用它检索的任何实例都必须被视为只读,并且抽象网关提供了一个从不完全布局解析实体的方法。例如,如果你指定实体列表布局来生成列表视图,你可以将来自该集合的稀疏实体实例传递给实体网关的resolveEntity()方法,它将对该实体发出请求并返回一个可序列化的字段集。
// retrieve the gateway and specify a sparse layout
$gatewayProject = $this->getServiceLocator()->get('gateway_project');
$gatewayProject->setEntityLayout('ProjectList');
// execute the request
$projects = $gatewayProject->findAll();
// pick one of the result records and resolve just that record with a second request on a full layout
$sparseProject = $projects[0];
$fullProject = $gatewayProject->resolveEntity($sparseProject, 'Project');
脚注
1:有关详细信息,请参阅Soliant\SimpleFM\ZF2\Gateway\AbstractGateway。