chkt/lola

微 MVC 框架,服务,提供者,模块,依赖注入

v0.6.4-alpha.1 2018-05-16 01:05 UTC

README

# Lola 使用模块化、提供者、依赖注入、MVC 和服务构建的最小化应用程序框架。

## 安装

$ php composer.phar install chkt/lola

## 使用

### 初始化您的应用程序

App 对象是一个单例,表示您的基本应用程序配置,以及模块注册表、注入器和定位器的引用。您可以从 \lola\app\App 扩展您的 app 对象或实现 \lola\app\IApp。

<?php //App.php

namespace app\app;


final class App
extends \lola\app\App
{

}

要使用框架完成任何有用的任务,您必须创建一个 app 对象,这将执行基本的引导和初始化其基本设施。

<?php //index.php

require_once '../vendor/chkt/lola/source/app/AppLoader.php';

如果您尚未初始化任何自动加载器,请要求 lola\app\AppLoader。AppLoader 将执行基本的引导并提供对应用程序对象的引用。

$app = \lola\app\AppLoader::Init([
	'rootOffset' => '..',

Apploader 将为您的应用程序提供基本配置数据。您可以将任何需要的配置键放入其中,稍后通过调用 $app->getProperty('myProperty') 来检索它们。

此外,还有一些键会影响引导过程。'rootOffset' 定义了您的入口点相对于应用程序根文件夹的路径

    'composer' => true,

是否使用 composer 自动加载器。如果您自己已经要求了 composer 自动加载器,则此值应为 false。

    'exceptionPage' => '/source/server/app/view/error500.html',

应用程序相对于 500 异常页面的路径。

    'locator' => [
    	'controller' => '\\lola\\ctrl\\ControllerProvider',
    	'service' => '\\lola\\service\\ServiceProvider'
    ]

定位器可用的提供者的合格名称。

])->getApp();

$app
	->useLocator()
	->using('service')
	->using('router')
	->useRouter()
	->enterRoutes(filter_input(INPUT_SERVER, 'REQUEST_URI'));

现在您可以检索对应用程序对象的引用并进入应用程序(例如通过访问路由服务)。

### 实体标识符

Lola 使用 URI 格式的标识符字符串来识别应用程序中的可定位实体。字符串 entityType://moduleId/path/to/entityName?entityId 将从模块 moduleId 的路径 path/to/entityName 检索类型为 entityType 的实体,其唯一 id 为 entityId

entityType 可以是任何配置的可定位资源类型,moduleId 是模块的规范名称,路径表示类在其本地树中的路径 - 正斜杠将被转换为反斜杠,以符合 PHP 命名约定。

框架将尽力推断请求的实体的属性。在任何类型隐式的地方,指定 entityType 是不必要的。当未指定 moduleId 时,模块注册表将在已注册的模块中搜索该类。entityId 仅在需要配置实体时才需要,而 entityName 通常可以简化为简单的字母数字字符串。

### 模块

Lola 使用模块、依赖注入和提供者。

要创建自己的模块,在模块文件夹结构的根目录中创建一个 Module 类。

 
namespace myModule;

use lola\module\AModule;

use myOtherModule\MyService;


final class Module
extends AModule
{

为了方便,您可以直接从 lola\module\AModule 继承。或者您也可以实现 \lola\module\IModule。

	static public function getDependencyConfig(array $config) {
		return [[
			'type' => Injector::TYPE_SERVICE,
			'id' => 'my'
		]];
	}

在 ::getDependencyConfig() 内部定义您的依赖项。所有定义的依赖项都将可用于 ->__construct()。

	public function __construct(MyService& $mySerivce) {
		$myService->doModuleTask('myModule');
	}

在构造函数内部,您可以运行任意代码,例如将模板文件文件夹添加到您的视图服务中。

	public function getModuleConfig() {
		return [
			'locator' => [
				'controller' => [
					'path' => 'controller',
					'prefix' => '',
					'postfix' => 'Controller'
				]
			]

在 ->getModuleConfig() 内部定义您控制器、服务和其他可定位资源的位置。所有定义的资源将自动对提供者和注入器可用。

示例包含对模块所属控制器的自定义配置,所有设置都反映了控制器的默认设置。

			'config' => [
				'service:my' => function(MyService& $myService) {
					$myService->configure('myModule');
				}
			]
		];
	}
}

您还可以在模块配置中添加额外的配置。所有配置都将添加到模块注册表,并且仅在创建实际引用的实体实例时才会调用。

这样您可以避免创建和配置将来不会使用的服务,以及在尝试配置由当前模块定义的实体时出现的依赖循环。

###控制器

<?php //MyController.php

namespace myModule\controller;

use lola\ctrl\AController;
use lola\inject\Injector;

use lola\route\Route;


class MyController
extends AController
{

	static public function getDependencyConfig(array $config) {
		return [[
			'type' => Injector::TYPE_INJECTOR
		],[
			'type' => Injector::TYPE_SERVICE,
			'id' => '//myOtherModule/my'
		]];
	}

所有控制器都继承自/lola/ctrl/AController,它本身是可注入的。

	private $myService = null;


	public function __construct(
		Injector& $injector,
		MyService& $myService
	) {
		$this->myService = $myService;
		
		$this->setRequestTransform($injector->produce('\\myModule\\controller\\MyControllerRequestTransform'));
		$this->setReplyTransform($injector->produce('\\myModule\\controller\\MyControllerReplyTransform'));
	}

控制器使用请求和回复转换来设置控制器在运行请求的操作之前的状态。所有转换都继承自/lola/ctrl/ControllerTransform。当您第一次创建控制器时,其转换将是空的。

当通过调用$ctrl->enter()在控制器上进入一个动作时,首先会在控制器上执行请求转换,然后调用动作,最后执行回复转换。只有以*Action结尾的方法才能进入。

如果您的控制器在响应HTTP请求时运行,例如,您可以设置您的回复转换以使用操作返回的值来渲染视图,然后使用控制器中的\lola\http\HttpReply实例来发送渲染的视图。

	
	
	public function myAction(Route& $route) {
		$this->myService->doSomething($route->getParam('param'));
	}
}

###状态转换

状态转换是简单的状态机,表示应用程序内的某些设置任务,例如在执行动作之前设置控制器的状态。

<?php //MyRequestTransform.php

namespace app\ctrl;

use lola\ctrl\ControllerProcessor;
use lola\inject\IInjectable;

class MyRequestTransform
extends ControllerProcessor
implements IInjectable
{
	
	static public function getDependencyConfig(array $config) {
		return [];
	}

状态转换默认不是可注入的,但您可以轻松地增强此功能。转换将包含状态图以及实现状态转换的实际代码。

	public function __construct() {
		parent::__construct([
			'start' => [
				'next' => [
					'success' => 'step1'
				]
			]
			'step1' => [
				'transform' => 'foo',
				'next' => [
					'success' => '',
					'failure' => 'fallback
				]
			],
			'fallback' => [
				'transform' => 'bar',
				'next' => [
					'success' => ''
				]
			]
		]);
	}

状态图定义了在不同场景下转换应该执行的顺序。

建议在每个转换中都有一个start状态,因为如果实例的->process()方法没有提供其他状态,起始状态将自动运行。

如果一个状态包含一个transform属性,状态转换将尝试执行带有transform值和Step连接的方法。例如,如果转换属性包含值为foo,状态转换将尝试进入名为fooStep的实例方法。

转换方法可以选择性地返回一个值。该值将映射到next中的值。如果方法没有返回值或null,其返回值将映射到success。如果返回值的next属性值为空字符串,则不会进入进一步的状态。

	public function fooStep(MyEntity& myEntity) {
		//...
	}
	
	public function barStep(MyEntity& myEntity) {
		//...
	}
}

实际转换函数是类的成员。myEntity可以使用实例的->setTarget()方法设置。对于作为框架定义的应用程序流程一部分执行的转换,这会自动发生。

###服务

所有服务都扩展自lola\service\AService。服务不是单例,但默认服务提供者使用\lola\prov\SimpleProviderResolver,这将确保您在提供相同的服务id时总是收到相同的服务实例。

<?php //MyService.php

namespace app\service;

use lola\service\AService;

final class MyService
extends AService
{

	static public function getDependencyConfig(array $config) {
		return [];
	}
	
	
	public function doSomething() {
		//...
	}
}

由于服务可以是从相关函数的简单集合到提供模型,再到暴露复杂应用程序逻辑,因此没有提供通用接口。您的应用程序必须确保所有服务都是可注入的。