此包最新版本(0.0.0)没有可用的许可信息。

0.0.0 2019-12-21 04:58 UTC

README

avatar

SeanMorris/Ids v00.0.0

/ eye dee ess / • PHP + Docker 框架

seanmorris/ids Apache-2.0 Licence Badge CircleCI Codecov Size badge Docker Pulls - Idilic Docker Pulls - Server

php 8.0 tests php 8.1 tests php 8.1 tests

Ids 库为开发基于 Web 的应用程序提供了通用的领域原语。路由、请求、配置建模、日志记录、会话和数据库访问都被抽象成简单、表达性强的接口,以实现高效且强大的代码。

为防止意外行为,系统将所有错误(除来自供应商目录的 E_DEPRECATED 错误外)都设置为在 E_NOTICE 时终止。

该项目旨在在 Docker 中运行,但并不需要它。它可以包含在任何 composer 项目中,并可以轻松地部分或全部使用。

Ids 项目的哲学是安全、速度和易用性,按此顺序。

请在 docs.ids.seanmorr.is 查看文档

依赖关系

展开
  • Composer
  • Docker
  • Docker Compose
  • GNU Make
  • Git
  • Linux 或兼容操作系统
  • PHP
  • SimpleTest
  • Minikube(仅用于 Kubernetes 目标)

安装

展开使用以下方式将 Ids 包含到您的项目中
$ composer require seanmorris/ids

全局安装 Ids 以访问 idilic 命令行工具

$ composer global require seanmorris/ids:dev-master

通过将以下内容添加到您的 ~/.bashrc 来将 composer 的全局 vendor/bin 添加到您的 PATH 中。

export PATH="$HOME/.composer/vendor/bin:$PATH"

创建一个新的 Ids 项目

展开

使用 composer 创建新项目,进入目录并启动 php、apache 和 mysql

$ composer create-project seanmorris/ids-project -s dev --remove-vcs
$ cd ids-project
$ make @dev build start-bg

就这样!

提供新项目模板的配套包可以在以下位置找到

https://github.com/seanmorris/ids-project

开发工具

展开

dev 构建目标提供连接到 xdebug 和 graylog 的工具。

XDebug

XDebug 默认集成到 dev 映像中。您可以通过在 .env.dev 中设置 XDEBUG_CONFIG_ 环境变量来配置它。默认情况下,它将尝试连接到 ${DHOST_IP} 上的 9000 端口,这是运行项目的主机。

Apt 缓存

离线重建您的镜像

使用互联网连接并带有 +aptcache 选项构建项目以填充您的缓存。

$ make @dev+aptcache build

... 待续

GrayLog

\SeanMorris\Ids\Logger\Gelf 提供了一个简单的接口来访问 graylog。只需将其添加到 IDS_LOGGERS_ 环境变量中即可启用。只要有一个可用的 graylog 服务器,它就会发送所有满足详细程度阈值的日志。

dev 目标的默认 graylog 配置如下所示

IDS_LOGGERS_=\SeanMorris\Ids\Logger\Gelf
IDS_GRAYLOG_HOST=graylog
IDS_GRAYLOG_PORT=12201

此包在灰度日志配置备份中包含默认的 GELF TCP 输入。您可以在首次启动 graylog 后运行 make graylog-restore 以创建输入。

可以使用以下命令备份和恢复 graylog 配置

$ make graylog-backup     # alias glbak
$ make graylog-restore    # alias glres

可以使用以下命令启动和停止 graylog

$ make graylog-start      # alias gls
$ make graylog-start-fg   # alias glsf
$ make graylog-start-bg   # alias glsb

$ make graylog-stop       # alias gld

$ make graylog-restart    # alias glr
$ make graylog-restart-fg # alias glrf
$ make graylog-restart-bg # alias glrb

一些用户

sysctl -w vm.max_map_count=262144

Idilic CLI

展开

Ids 在使用 composer 全局安装时附带 idilic 命令。当执行时,它将通过当前路径向上查找包含 Ids 的其他项目。当找到它时,它将附加到该项目并利用其功能。

如果它在项目目录中遇到本地 idilic 传递,它将控制权交给 Docker 环境,执行将继续。

运行 idilic help 以查看任何已安装包公开的操作。

多阶段 / 环境目标

展开

base、prod、dev 和 test

默认情况下,Ids提供了4个构建目标:base、prod、dev和test。每个目标都暴露不同的端口,因此它们可以并行运行而不会发生冲突。

  • base不暴露任何端口,构建时不包含require-dev

  • prod暴露端口80(可通过IDS_EXPOSE_HTTP配置)和端口443*(可通过IDS_EXPOSE_HTTPS配置),构建时不包含require-dev

  • test暴露端口2021(可通过IDS_EXPOSE_HTTP配置)和端口3031(IDS_EXPOSE_SQL),构建时包含require-dev

  • dev暴露端口2020(可通过IDS_EXPOSE_HTTP配置)和端口3030(IDS_EXPOSE_SQL),构建时包含require-dev

*尚未实现。

切换目标

系统将使用TARGET环境变量来决定使用哪个构建目标。

如果您在BASH shell上,只需运行以下命令之一来设置单个命令的上下文目标

  • make @base start
  • make @dev build
  • make @test test
  • make @prod push-images

如果您不想为每个命令都输入@target,可以使用以下命令让系统记住一个目标

  • make stay@base
  • make stay@dev
  • make stay@test
  • make stay@prod

扩展环境

可以通过在项目中创建一个新的infra/compose/[TARGET].yml来指定额外的目标。像构建任何其他docker-compose文件一样构建此文件。

然后在config/中创建一个新的.env.[TARGET]文件。在这里添加您的默认设置。

如果您需要一些特定于目标构建步骤,请在infra/docker中的任何相关的docker文件中添加一个FROM base as TARGET部分。您可以对任何现有的构建目标进行扩展,您不仅限于扩展base

构建

展开

项目可以使用make进行构建。Debian用户可以通过运行apt-get install build-essential来获取此工具。构建过程还需要dockerdocker-compose。仅对kubernetes测试需要minikube

默认的构建目标是base。运行make stay@devmake stay@test以切换到开发/测试目标。您可以在任何make命令的开头使用@TARGET来为该命令使用目标。

$ make @dev build # build the project

$ make @dev start # start the services

Docker & docker-compose的安装

启动/停止/重启

展开

在执行任何命令之前,请使用make stay@target设置一个目标。或者,您也可以以make @target command的形式运行命令。

$ make start      # Start the project in the background,
                  # with no output

$ make start-fg   # Start the project in the foreground.

$ make start-bg   # Start the project in the background,
                  # stream output to foreground.

$ make stop       # Stop all services defined for the target.

$ make stop-all   # Stop all services spawned for the target
                  # even ones no longer in target compose file.

$ make restart    # Stop, then restart the project in the background,
                  # with no output.

$ make restart-fg # Stop, then restart the project in the foreground.

$ make restart-bg # Stop, then restart the project in the background,
                  # stream output to foreground.

镜像 & 标签

展开
$ make list-images # List all images for the current project, target & branch.

$ make list-tags   # List all tags for the current project, target & branch.

$ make push-images # push all images for the current project, target & branch.

$ make pull-images # push all images for the current project, target & branch.

自动打标签/自动发布/Git钩子

展开

使用make hooks注册git钩子。

在构建时根据日期、当前git标签(如果失败则回退到提交哈希)自动生成镜像标签。

主分支将生成

  • repository/project:gitTag-target
  • repository/project:date-target
  • repository/project:latest-target

除了主分支之外的分支将生成

  • repository/project:gitTag-target-branch
  • repository/project:date-target-branch
  • repository/project:latest-target-branch

git commit时构建镜像,并在git push时推送,如果当前分支出现在项目根目录下的.publishing文件中,格式为:BRANCH:TARGET。例如,当在主分支上运行git push时,此文件将推送prod和test的镜像。

master:test
master:prod

可用镜像

展开

对于目标basedevtest,Docker镜像seanmorris/ids.idilic和seanmorris/ids.server可在DockerHub上使用和扩展。

从CLI拉取

$ docker pull seanmorris/ids.idilic:latest
$ docker pull seanmorris/ids.server:latest

或者在一个Dockerfile中使用以下之一进行扩展

(不推荐在FROM中使用latest)

FROM seanmorris/ids.idilic:TAGNAME
FROM seanmorris/ids.server:TAGNAME

服务开关

展开当运行Ids时,可以包含额外服务。只需在发出make命令时,将+toolname添加到您的@target中,必要的composer文件将包含在您的命令上下文中。例如,要以开发模式启动带有graylog的系统
make @dev+graylog start

或inotify

make @dev+inotify start

或两者都使用

make @dev+graylog+inotify start

模板化

展开

这不是你爷爷的makefile。

GNU Make具有独特且强大的语法。它借用,或者在某些情况下直接使用底层的bash引擎,允许用户定义复杂的构建步骤,并跟踪它们之间的关系,以确保一切是最新的。

Make允许递归变量扩展、条件语句、循环,甚至可以调用shell。这种语法不再限于Makefile。

简单来说,将扩展名*.idstmp.* 放在您现有的文件扩展名之前。Ids将在项目的所有子目录中查找这些文件,并在启动时重建它们。结果文件将具有扩展名*.___gen.*,其中*.idstmp.*位于源文件中。

这些结果文件应排除在版本控制之外,因为它们可能包含不应存在于另一个目标中的工件。

例如:infra/docker/aptcache.idstmp.dockerfile以以下行开始

FROM ${BASELINUX}

Dockerfile中的FROM部分通常不允许变量,在make预处理之前使用。只要文件扩展名以.idstmp.开头,我们就可以信赖将产生一个.___gen.文件。这允许我们将所有镜像和容器同步到一个基础镜像。

文件的末尾以下行显示了如何使用shell跟踪谁生成了文件以及何时生成

# generated @ $(shell date)
# by ${shell whoami} @ ${shell hostname}

有关更多信息,请参阅文本转换函数

配置/环境变量/密钥

展开

加载设置

设置可以以环境变量、.env文件或yml文件的形式提供。

环境变量和目标文件

以下文件可以创建/修改以配置系统。当项目构建、重启等时,将检查其修改,并在必要时将其重新构建到项目的根目录。应将生成到项目根目录的文件排除在版本控制之外。

  • config/.env - 不应提交到版本控制。包含适用于系统的配置,无论系统的目标是什么。
  • config/.env.default - 应提交到版本控制。包含非秘密配置文件和在config/.env中设置的变量的空白/默认值。
  • config/.env_TARGET - 不应提交到版本控制。包含基于系统目标的配置。
  • config/.env_TARGET.default - 应提交到版本控制。包含非秘密配置文件和在config/.env_TARGET中设置的变量的空白/默认值。

设置的值将根据以下优先级(较高的优先于较低的)读取

  • .env_TARGET
  • .env_TARGET.default
  • .env
  • .env.default

在配置中使用的环境变量应具有前缀IDS_。具有名称IDS_SOME_VAR和IDS_SOME_OTHERVAR的环境变量可以在系统内通过

IDS_SOME_VAR=value
IDS_SOME_OTHERVAR=other value
<?php
use \SeanMorris\Ids\Settings;

$someVar = Settings::read('some', 'var');
$someOtherVar = Settings::read('some', 'otherVar');

配置对象

它们都可以作为对象访问,可以迭代

<?php

$some = Settings::read('some');

$some->var;
$some->otherVar;

foreach($some as $configKey => $value)
{

}

配置数组

可以通过在环境变量名称末尾添加下划线来创建数组。值将在空白处分割。

IDS_ARRAY_=first second third
<?php
$array = Settings::read('ARRAY');

如果值是引号,则保留空白。

IDS_ARRAY_=first "second element" third

引号可以通过双重引用来转义。

IDS_ARRAY_=first "second element ""with quotes inside""." third

基于主机名和端口的配置

特定主机名的环境变量以前缀一个额外的下划线开始:IDS__。主机名中的点和其他非单词字符由单个下划线替换,但破折号除外,它被替换为三个下划线。另一个双下划线结束主机名,然后是变量名。

例如,可以使用以下方式覆盖example.com的环境变量:IDS__EXAMPLE_COM__SOME_VARIDS__EXAMPLE_COM__SOME_OTHERVAR。它们的访问方式与上面相同。

IDS__EXAMPLE_COM__SOME_VAR=overridden value
IDS_SOME_OTHERVAR=other overridden value
<?php
use \SeanMorris\Ids\Settings;

$someVar = Settings::read('some', 'var');
$someOtherVar = Settings::read('some', 'otherVar');

$some = Settings::read('some');

$some->var;
$some->otherVar;

如果example.com希望根据用户是否在SSL下改变某些行为,可以通过端口号覆盖变量。在主机名和变量名之间添加另一个双下划线可以实现这一点:IDS__EXAMPLE_COM__80__SOME_VARIDS__EXAMPLE_COM__80_SOME_OTHERVAR 用于HTTP,以及 IDS__EXAMPLE_COM__443__SOME_VARIDS__EXAMPLE_COM__443_SOME_OTHERVAR 用于HTTPS。

再次强调,访问方式没有任何变化。代码以相同的方式读取它们。

IDS__EXAMPLE_COM__80__SOME_VAR=normal value
IDS__EXAMPLE_COM__443__SOME_VAR=value for SSL

IDS__EXAMPLE_COM__443__SOME_VAR=some other value
IDS__EXAMPLE_COM__443_SOME_OTHERVAR=some other value for SSL
<?php
use \SeanMorris\Ids\Settings;

$someVar = Settings::read('some', 'var');

// ...and so on

非秘密配置

对于非秘密的环境变量(因此可以推送到版本控制),可以在config/.env中设置默认值。特定目标的变量可以设置在config/.env.[TARGET]中。请勿在此处放置如密码之类的秘密。这些文件将被提交到版本控制。

当项目构建或启动时,这些文件将被用于生成项目根目录中的最终.env文件。

一次性秘密

如果您需要在构建过程中使用一个快速随机的值(例如创建MYSQL密码),请确保将其键添加到相关的.env文件中,但将其值留空。以CONFIG_KEY:ENTROPY_KEY的形式将键名添加到项目根目录中的.entropy文件中。CONFIG_KEY是您的配置值的名称,而ENTROPY_KEY是允许您在不同配置键之间重用相同随机值的任意字符串。

当项目启动时,如果不存在或现有的为空,.env文件将生成到项目的根目录。.entropy文件中的任何键都将设置为一个随机的32字符字符串。这是当当前test时,为make test命令生成mysql服务器的数据库名称、用户名和密码的方式。

运行TARGET=test idilic info查看此示例。

普通秘密

只要.env文件存在且不为空,系统就不会尝试重新生成它们,因此理论上可以在这里直接添加任何秘密。这适用于开发,但对于生产,建议将秘密存储在环境变量中。

环境变量和.env文件中的值可以通过PHP的getenv()访问。如果您选择不将值添加到.env文件中,请确保已设置目标docker-compose文件中的environment部分的相关值。

Json/Yaml配置

设置

可以在config/目录下提供Json/Yaml文件,在名为hostname/hostname;port/的目录下,其中hostnameport是您期望请求进入的域名和端口号。文件应命名为settings.jsonsettings.yml。名为_;80;80的目录将仅匹配端口号为80的请求,无论主机名如何。名为_;_;的目录可以作为其他都不匹配时的后备。

注意如果加载了任何yml配置文件,系统将停止查找,不会查找其他文件。特定主机或端口的yml文件将不会与更通用的通配符文件合并。

默认值

默认的非秘密值可以提供在名为settings.defaults.ymlsettings.defaults.json的文件中。默认值与设置相同,但它们存储在版本控制中。

默认值按与标准设置文件相同的规则加载。一旦找到单个默认值文件,就不会再加载其他文件。

设置和默认文件不需要在相同的一般性级别上加载。 settings.yml 可能在 _;80 中找到,而 settings.defaults.yml 可能在 hostname 中找到,反之亦然。

设置始终优先于默认值。

来自shell或 .env 文件的环境变量比 yml 文件具有优先级。

待续...

模式差异 & 补丁

展开

确保您已从文档开头安装了 idilic 命令行工具。使用以下命令管理您的数据库模式。

idilic storeSchema [PACKAGE] - 存储当前模式。

idilic applySchema [PACKAGE] - 应用存储的模式。

idilic applySchemas - 应用所有已安装包的存储模式。

模式将存储在 data/global/schema.json

路由

展开
IDS_ENTRYPOINT=SeanMorris\Ids\Test\Route
<?php
namespace SeanMorris\Ids\Test\Route;
class RootRoute implements \SeanMorris\Ids\Routable
{
	public
		$routes = [
			'foo' => 'SeanMorris\Ids\Test\Route\FooRoute'
		]
		, $alias = [
			'bar' => 'foo'
		];

	public function index($router)
	{
		return 'index';
	}

	public function otherPage($router)
	{
		return 'not index';
	}
}

建模 / ORM

展开

定义模型

  • 属性
  • 选择器
  • 列包装器
  • 行为
<?php
namespace SeanMorris\Ids\Test\Model;
class Foozle extends \SeanMorris\Ids\Model
{
	use Common;

	protected
		$id
		, $class
		, $publicId
		, $value
	;

	protected static
		$table = 'Foozle'

		, $createColumns = [
			'publicId' => 'UNHEX(REPLACE(UUID(), "-", ""))'
		]

		, $byId = [['id' => '?']]

		, $readColumns = [
			'publicId' => 'HEX(%s)'
		]

		, $updateColumns = [
			'publicId' => 'UNHEX(%s)'
		]
	;
}

加载模型

模型加载方法以动词形式动态生成,形式为

VERB [Flat] [Submodel|Record] [By SELECTOR]([...$args])

动词

  • get - 获取模型数组。
  • getOne - 获取单个模型。
  • load - 返回一个获取模型数组的回调。
  • loadOne - getOne 的别名。
  • generate - 返回一个生成模型生成器的回调。
  • count - 返回模型计数。
  • report - 返回一个(可选)聚合结果集作为二维数组。

修饰符

  • Flat - 即使在选择器中指定,也不要连接子模型(父类表仍然连接)
  • Submodel - 包含给定模型的任何子类;
  • Record - 加载记录,但跳过初始化逻辑(before/afterRead 方法)。

选择器

日志记录

展开可以通过调用对应于所需详细程度的函数在系统的任何地方编写日志。有6个详细程度级别可用。
<?php
use \SeanMorris\Ids\Log;

Log::trace(...$messages); # Log a message along with a stacktrace.
Log::query(...$messages); # Log query-level information
Log::debug(...$messages); # Log debug information
Log::info(...$messages);  # Log general information
Log::warn(...$messages);  # Issue a warning
Log::error(...$messages); # Issue an error

Ids 将日志写入文件或由 IDS_LOG 配置指定的处理程序

IDS_LOG=php://stderr
# can also be a file
IDS_LOG=/tmp/ids.log

当前详细程度级别可以通过 IDS_LOGLEVEL 变量进行配置。

注意:如果 LOGLEVEL 设置为 trace,则每个日志条目都将伴随堆栈跟踪。这可能会迅速填满磁盘。请谨慎使用!

IDS_LOGLEVEL=trace
IDS_LOGLEVEL=query
IDS_LOGLEVEL=info
IDS_LOGLEVEL=debug
IDS_LOGLEVEL=warn
IDS_LOGLEVEL=error
IDS_LOGLEVEL=off

ANSI 颜色

默认情况下,日志记录具有 ANSI 颜色开启。如果这导致您阅读日志时出现问题,请设置以下配置以禁用它

IDS_LOGCOLOR=0

审查日志

在您的配置中设置 IDS_LOGCENSOR_ 数组,以定义不应出现在日志文件中的值的数组。如果这些值作为函数参数、数组键或对象属性找到,则将它们记录为 * censored * 而不是其实际值。

默认审查过滤器是

IDS_LOGCENSOR_=router password passwd

您可以通过以下命令测试审查过滤器。执行以下命令将输出您的数据库设置,不应用审查

$ idilic config databases

将 -vv 添加到 idilic 命令将强制它将其日志打印到 STDERR(不进行详细程度检查)。

$ idilic -vv config databases

我们可以按如下方式删除命令的原始输出,以清理终端

$ idilic -vv config databases 1 > /dev/null

我们还可以使用以下方式提取原始输出

$ idilic -vv config databases 2 > /dev/null

重定向 / 强制 CLI 日志

可以使用 -v-vv 在命令行上强制日志记录。

  • -v 将打印任何在当前详细程度阈值内的日志到 STDERR
  • -vv 将打印任何日志,无论详细程度阈值如何,都到 STDERR
$ idilic -v  info
$ idilic -vv info

可以使用 2> 将单个命令的日志重定向到文件或处理程序。

$ idilic -v  info 2> /tmp/summary$(date +%Y%m%d).log
$ idilic -vv info 2> /tmp/details$(date +%Y%m%d).log

如果您对日志比对输出更感兴趣,可以使用

$ idilic -v  command 1> /dev/null
$ idilic -vv command 1> /dev/null

Graylog

可以通过在配置中提供自定义日志处理程序将日志发送到 Graylog

IDS_LOGGERS_=\SeanMorris\Ids\Logger\Gelf

自定义日志记录器

可以通过实现 \SeanMorris\Ids\Logger 接口创建自定义日志记录器。

<?php
namespace SeanMorris\Ids\Logger;
class AdditionalLogger implements \SeanMorris\Ids\Logger
{
	public static function start($logBlob)
	{/* ... */}

	public static function log($logBlob)
	{/* ... */}
}

将它们添加到 IDS_LOGGERS_ 数组以激活它们

IDS_LOGGERS_=\SeanMorris\Ids\Logger\AdditionalLogger

调试

展开
XDEBUG_CONFIG_REMOTE_HOST=${DHOST_IP}
XDEBUG_CONFIG_REMOTE_PORT=9000

XDEBUG_CONFIG_PROFILER_ENABLE=0
XDEBUG_CONFIG_REMOTE_ENABLE=1

链接包

展开

一些功能需要事先了解存在的包、文件和类。每次使用这些功能时都扫描此列表将会使速度变得非常缓慢。使用以下命令构建此索引:

$ make composer-dumpautoload
$ idilic link

测试

展开
$ make @test build test
$ idilic runTests
<?php
namespace SeanMorris\ExamplePackage\Test;
class ExampleTest extends \UnitTestCase
{
	public function testSomething()
	{
		// ...
	}
}

文件访问

展开
<?php
use \SeanMorris\Ids\Disk\File;

$file = File::open($filename);

//Check if file exists
if($file->check())
{
	// ...
}

//Get the path to the file
$path = $file->name();

//Copy the file to another location.
$copiedFile = $file->copy($newLocation);

// Read byte-by-byte
while(!$file->eof())
{
	$byte = $file->read(1);
}

// Read entire file:
$content = $file->slurp();

// Append
$file->write($content);

// Overwrite
$file->write($content, FALSE);

迁移*

展开待完成

资产管理

展开待完成

HTTP API*

展开待完成

IPC / AMPQ*

展开待完成

实现Idilic CLI命令

展开

Idilic命令可以通过CLI以idilic命令idilic Vendor/Package命令的形式运行。请注意,在CLI中,包名可以通过正斜杠(/)分隔。这样做是为了防止用户被迫记住要转义反斜杠(\)。

运行idilic help以获取可用Idilic命令的列表。

可以通过在Vendor\Package\Idilic\Route命名空间下添加名为RootRoute的路由类来实现新命令

<?php
namespace SeanMorris\ExamplePackage\Idilic\Route;
class RootRoute implements \SeanMorris\Ids\Routable
{
	/** Help text goes here. */
	public function commandName($router)
	{}
}

依赖注入

展开

某些类提供了注入构造函数。它们将接受一个或多个类作为参数,并返回一个新的类以供使用。

例如,SeanMorris\Ids\Collection类提供了一个方法,将返回一个新子类,该子类将仅与给定的类型一起工作

在此示例中,DatetimeCollection类在::of()方法完成后才存在,但PHP仍然允许我们访问其::CLASS

我们还使用use在它存在之前将DatetimeCollection类别名为。这防止了它在此场景中继承Author\Package命名空间,尽管这并非必需。

<?php
namespace Author\Package;

use \DatetimeCollection;
use \SeanMorris\Ids\Collection;

// Create DatetimeCollection based on the existing Collection class
Collection::of(Datetime::CLASS, DatetimeCollection::CLASS);

// Create an instance of the new class:
$datetimeCollection = new DatetimeCollection();

创建可注入类

从头创建一个新的可注入类非常简单。您可以选择从一个使用SeanMorris\Ids\Injectable特质的现有类继承,或者从头开始创建一个具有以下构造的新类

注意:如果重写构造函数,您必须在子类构造函数中调用parent::__construct()$this->initInjections();,以确保在对象实例化时您的注入就绪。

<?php

$injectableClass = (new class { use Injectable; })::inject([]);

现在您可以使用new $injectableClass来实例化一个具有很少功能性的类。这里的问题是您不能在PHP中从匿名类继承。为了解决这个问题,我们可以向::inject()传递第二个参数来命名类

<?php

use \SeanMorris\Ids\Injectable;

(new class { use Injectable; })::inject([], AwesomeInjectable::CLASS);

class AwesomeClass extends AwesomeInjectable
{
	public function someMethod()
	{
		// here there be behaviors...
	}
}

类提升

最后一个示例展示了所谓的类提升,这简单地允许我们将匿名类提升为命名类,以便系统的其他部分可以通过名称引用它。

提升类有两种方法

使用Injectable特质

<?php
use \SeanMorris\Ids\Injectable;

$anonymousClass = new class
{
	use Injectable;

	public function doSomething()
	{
		echo "I'm doing something.";
	}
};

// Pr
$anonymousClass::inject([], NamedClass::CLASS);

或使用Loader

<?php

$anonymousClass = new class
{
	public function doSomething()
	{
		echo "I'm doing something.";
	}
};

Loader::define([ NamedClass::CLASS => $anonymousClass ]);

定义注入

::inject()的第一个参数中,我们可以定义我们希望我们的类拥有的任何默认注入,以简化我们想要它具有可覆盖的默认行为的情况。

<?php
use \SeanMorris\Ids\Injectable;

(new class { use Injectable; })::inject([

	InjectedDate::CLASS => Datetime::CLASS

], AwesomeInjectable::CLASS);

现在您可以访问注入作为新创建的类的静态属性

<?php

class DateFormatter extends AwesomeInjectable
{
	protected static $InjectedDate;

	public function dateToTimestamp($date)
	{
		$datetime = new static::$InjectedDate($date);

		return $datetime->getTimestamp();
	}
}

由于注入表示为静态属性,因此注入类在静态范围内可以很好地访问

<?php

class DateFormatter extends AwesomeInjectable
{
	protected static $InjectedDate;

	public static function dateToTimestamp($date)
	{
		$datetime = new static::$InjectedDate($date);

		return $datetime->getTimestamp();
	}
}

您可以继续创建可能或可能不覆盖默认注入的进一步子类

<?php
// Inherit injected classes normally:

class CoolDateFormatter extends DateFormatter
{
	// ...
}

// Or create new subclasses by injecting the class and passing a new name:
// (AwesomeDateFormatter is being created based on DateFormatter here)

DateFormatter::inject([

	InjectedDate::CLASS => \Awesome\Project\AwesomeDatetime::CLASS

], AwesomeDateFormatter::CLASS);

class EvenCoolerDateFormatter extends AwesomeDateFormatter
{
	// ...
}

子类化现有/默认注入

如果现有注入是静态属性,您可以直接访问它并对其调用::inject()以创建现有注入的子类

<?php

use \SeanMorris\Ids\Collection;
use \SeanMorris\Ids\WrappedMethod;

$RankIterator = $collectionClass::$RankIterator::inject([
	'map' => WrappedMethod::wrap($callback)
]);

$mappedCollection = Collection::inject([

	'RankIterator' => $RankIterator

]);

直接扩展它

如果现有注入是静态属性,您可以直接访问它并对其调用::inject()以创建注入子类

<?php
use \SeanMorris\Ids\Collection;
use \SeanMorris\Ids\WrappedMethod;

$collectionClass::$RankIterator::inject([

	'map' => WrappedMethod::wrap($callback)

], \InjectedRankIterator::CLASS);

class SubInjectedRankIterator extends InjectedRankIterator
{
	//...
}

$mappedCollection = Collection::inject([

	'RankIterator' => SubInjectedRankIterator::CLASS

]);

从现有类创建可注入类

任何可以扩展的类都可以成为可注入类

<?php
use \SeanMorris\Ids\Injectable;

class RegularOldClass
{
	// ...
}

(new class() extends RegularOldClass { use Injectable; })::inject(
	[], InjectableRegularOldClass::CLASS
);

$object = new InjectableRegularOldClass();

工厂、单例与可注入方法

行为可以动态地通过将闭包包装在简单的类中作为注入提供,以便让系统知道如何处理它。

方法被类包装,以便它们可以参与 Loader 系统。有关该主题的更多信息,请参阅 全局注入

注入方法

WrappeMethod 类允许您传递一个系统不会调用的方法,使其可以在代码中使用。

RankIterator 以这种方式实现了以下方法,以便可以注入映射方法

<?php

class RankIterator extends AppendIterator
{
	use Injectable;

	protected static $map;

	// ...

	public function current()
	{
		$value = $this->getInnerIterator()->current();

		if(static::$map)
		{
			$mapper = static::$map;
			$value  = $mapper($value, $this->key());
		}

		return $value;
	}

	// ...
}

创建具有映射行为的新的迭代器类如下所示

<?php

use \SeanMorris\Ids\WrappedMethod;
use \SeanMorris\Ids\Collection\RankIterator;

$MappedRankIterator = RankIterator::inject([

	'map' => WrappedMethod::wrap(function($input){
		$output = doSomething($input);

		return $output;
	})

]);

$iterator = new $MappedRankIterator;

工厂方法

可以以类似的方式提供工厂方法。

<?php
use \SeanMorris\Ids\Inject\FactoryMethod;

$coolDateFormatter = AwesomeDateFormatter::inject([

	assembledObject::CLASS => FactoryMethod::wrap(function(){

		$object = new StdClass;

		$object->someProperty = 'important value';
		$object->someOtherVar = 'slightly less important value';

		return $object;
	})

]);

单例方法

可以以类似的方式加载单例。被 SingletonMethod 包装的方法只被调用一次,其返回值用作所有情况下的注入。

作为静态属性提供的单例将在定义时实例化,而不是在属性访问时。

<?php
use \SeanMorris\Ids\Inject\SingletonMethod

class AwesomeLogger
{
	protected $fileHandle;

	writeLog($line)
	{
		fwrite($this->fileHandle, $line);
	}
}

$CoolerLogger = AwesomeLogger::inject([

	logFile::CLASS => SingletonMethod::wrap(function(){

		$fileHandle = fopen(LOG_FILE_LOCATION, 'a');

		fwrite("Log started!\n", $fileHandle);

		return $fileHandle;
	})
]);

$logger = new $CoolerLogger;

$logger->writeLine('This is a log line!');

全局注入 & \___\... 命名空间

可以全局定义注入,以便类可以自动获取它们。使用 \___\... 命名空间,我们可以设置可以全局定义注入的位置。您还可以使用 \Author\Project\___\... 命名空间。

例如,如果上面的 AwesomeLogger 类定义如下所示

<?php

$injections = [logFile::CLASS => \___\LogFileInjectable::CLASS];

(new class { use Injectable; })::inject($injections, AwesomeLogger::CLASS);

可以在项目的 source/ 目录中的 ids.boot.php 文件中全局定义注入。这可以通过根项目的启动文件最后执行来覆盖。

<?php
use \SeanMorris\Ids\Loader;

// We can alias classes even if they don't exist yet:
// If we were in a namespace, this would prevent it
// from inheriting the FQNS.
use \___\LogFileInjectable;

Loader::define([ LogFileInjectable::CLASS => ActualLogFileClass::CLASS ]);

覆盖全局注入

全局注入只能在它们在代码中使用之前被覆盖。这不包括对 ::CLASSuse 语句的访问,这些语句从其他命名空间导入类。

<?php
// Dependency package's ids.boot.php:
use \SeanMorris\Ids\Loader;

Loader::define([ LogFileInjectable::CLASS => LogFileClass::CLASS ]);
<?php
// Root package's ids.boot.php:
use \SeanMorris\Ids\Loader;

Loader::define([ LogFileInjectable::CLASS => AwesomeLogFileClass::CLASS ]);

回退全局注入

有时您可能希望允许注入在整个系统或其某些部分中被覆盖。如果需要此行为以及回退到默认值,以下模式将处理这种情况。

在此示例中,系统的任何部分都可以请求“红色涂料”、“蓝色涂料”或“任何涂料”。他们可能得不到他们要求的那种颜色,但他们会得到涂料。

<?php
// Dependency package's ids.boot.php:
use \SeanMorris\Ids\Loader;

Loader::define([ \___\Paint::CLASS      => BasicPaint::CLASS ]);

Loader::define([ \___\Paint\Red::CLASS  => \___\Paint::CLASS ]);
Loader::define([ \___\Paint\Blue::CLASS => \___\Paint::CLASS ]);

这将允许我们覆盖所有注入“涂料”的实例。

<?php
// Root package's ids.boot.php:
use \SeanMorris\Ids\Loader;

Loader::define([ \___\Paint::CLASS => AwesomePaint::CLASS ]);

这将允许我们覆盖只注入“红色涂料”的实例。

<?php
// Root package's ids.boot.php:
use \SeanMorris\Ids\Loader;

Loader::define([ \___\Paint\Red::CLASS => AwesomeRedPaint::CLASS ]);

会话

展开待完成

电子邮件

展开
<?php
use \SeanMorris\Ids\Mail;

$mail = new \SeanMorris\Ids\Mail;
$mail->body(<<<EOM
	Message body here.
EOM);

$mail->from(\SeanMorris\Ids\Settings::read('noreply'));

$mail->subject('Hello from Ids!');

$mail->to($recipientEmail);

$mail->send(TRUE);

主题 & 前端

展开待完成

制作命令

展开

从项目根目录运行这些命令以构建和控制项目基础设施。

  • make build make b - 构建项目
  • make env make e - 打印项目环境配置。
  • make test make t- 运行测试。
  • make test make t- 删除生成的配置,* 即使它们已被修改。*
  • make start make s- 启动项目服务。
  • make start-fg make sf- 启动项目服务,保留终端控制并输出流。
  • make start-bg make sb- 启动项目服务,保留终端控制并输出流。
  • make restart-fg make rf - 重新启动项目服务,保留终端控制并输出流。
  • make restart-bg make rb- 重新启动项目服务,保留终端控制并输出流。
  • make stop make d- 停止项目服务。
  • make stop-all make da- 停止项目服务,包括任何不再出现在组合文件中的服务。
  • make kill make k- 立即终止项目服务。
  • make nuke make nk - 立即终止主机上的所有容器。尚未实现。
  • make current-tag ct - 输出当前目标和分支的项目标签。
  • make list-tags make lt - 列出当前目标和分支的镜像标签。
  • make list-images make li - 列出当前目标和分支的镜像。
  • make push-images make psi - 列出当前目标和分支的镜像。
  • make pull-images make pli - 列出当前目标和分支的镜像。
  • make hooks - 初始化git钩子。
  • make composer-install make ci - 安装composer包。
  • make composer-update make co - 更新composer包。
  • make composer-dump-autoload make cda - 重新生成并导出composer自动加载文件。
  • make npm install PKG="[PACKAGE]" make ni - 在项目内部运行npm install
  • make bash make sh - 获取bash提示到idilic容器。
  • make run CMD="SERVICE [COMMAND]" make r - 在服务容器中运行命令。

SeanMorris/Ids

版权所有 2011-2022 Sean Morris

本软件基于Apache License, Version 2.0(“许可证”);除非符合许可证规定,否则不得使用本软件。您可以在以下地址获得许可证副本:

https://apache.ac.cn/licenses/LICENSE-2.0

除非适用法律要求或书面同意,否则在许可证下分发的软件按“现状”基础分发,不提供任何明示或暗示的保证或条件。有关许可证的具体语言、权限和限制,请参阅许可证。

--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
SVG                              30              0           8957          65159
PHP                             111           3481            511          14781
JSON                             12              0              0          13051
Markdown                          3            983             16           2008
YAML                             27            107             11           1109
make                              2            145              9            612
Dockerfile                       11             64              5            308
Properties                        2              0              0             46
Bourne Shell                      4              9              0             40
Bourne Again Shell                2             17             17             23
XML                               2              0              0             22
INI                               4              0              0             17
HTML                              1              0              0             13
CSS                               1              0              0              1
JavaScript                        1              0              0              1
--------------------------------------------------------------------------------
SUM:                            213           4806           9526          97191
--------------------------------------------------------------------------------

由sean于2023年2月20日星期一上午9:13:03 EST构建