oasis / slimapp
slim 应用框架
Requires
- php: >=7.0
- oasis/http: ^2.0
- oasis/logging: ^1.2.0
- oasis/utils: ^1.6
- symfony/config: ^4.0
- symfony/console: ^4.0
- symfony/dependency-injection: ^4.0
- symfony/filesystem: ^4.0
- symfony/finder: ^4.0
Requires (Dev)
- doctrine/orm: ^2.5
- oasis/aws-wrappers: ^2.2.1
- oasis/doctrine-addon: ^2.0.2
- oasis/dynamodb-odm: ^1.0
- phpunit/phpunit: ^5.7
Suggests
- ext-pcntl: *
- dev-master
- v2.6.3
- v2.6.2
- v2.6.1
- v2.6.1-alpha2
- v2.6.1-alpha1
- v2.6.0-alpha1
- v2.5.1
- v2.5.1-alpha1
- v2.5.0
- v2.4.0
- v2.2.4
- v2.2.2
- v2.2.1
- v2.2.0
- v2.1.0
- v2.0.5
- v2.0.4
- v2.0.2
- v2.0.1
- v2.0.0
- v1.12.1
- v1.12.0
- v1.11.4
- v1.11.3
- v1.11.2
- v1.11.1
- v1.11.0
- v1.10.0
- v1.9.2
- v1.9.1
- v1.9.0
- v1.8.8
- v1.8.7
- v1.8.6
- v1.8.5
- v1.8.4
- v1.8.3
- v1.8.2
- v1.8.1
- v1.8.0
- v1.7.19
- v1.7.18
- v1.7.17
- v1.7.16
- v1.7.15
- v1.7.14
- v1.7.13
- v1.7.12
- v1.7.11
- v1.7.10
- v1.7.9
- v1.7.8
- v1.7.7
- v1.7.6
- v1.7.5
- v1.7.4
- v1.7.3
- v1.7.2
- v1.7.1
- v1.7.0
- v1.6.7
- v1.6.6
- v1.6.5
- v1.6.4
- v1.6.3
- 1.6.2
- v1.6.1
- v1.6.0
- v1.5.1
- v1.5.0
- v1.4.9
- v1.4.8
- v1.4.7
- v1.4.6
- v1.4.5
- v1.4.4
- v1.4.3
- v1.4.2
- v1.4.1
- v1.4.0
- v1.3.6
- v1.3.5
- v1.3.4
- v1.3.3
- v1.3.2
- v1.3.1
- v1.3.0
- v1.2.1
- v1.2.0
- v1.1.1
- v1.1.0
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- dev-develop
- dev-feature/migration-to-silex-2
This package is auto-updated.
Last update: 2024-09-16 21:11:54 UTC
README
瘦应用框架(SlimApp)是一个一体化框架,旨在使PHP项目的开发,无论是Web还是控制台项目,都更快、更简单。
安装与设置
该框架包含了一系列有用的PHP组件。这使得在设置新项目时更加方便:您只需使用composer要求项目本身,然后运行项目设置命令。
在新的项目根目录下运行以下命令以安装项目
composer require oasis/slimapp
安装后,您可以通过运行以下命令初始化项目
./vendor/bin/slimapp slimapp:project:init
按照屏幕提示提供必要的信息,您的项目目录结构将自动创建。
以下是项目初始化过程中所需信息的说明列表
在本文档的其余部分中,我们假设项目名称为 test-project,供应商为 minhao。所有其他设置将保持默认值。
目录结构
自动初始化的项目将具有以下目录结构
+ PROJECT_DIR/
+ assets/ # static assets directory
+ bin/ # executable directory
- test-project.php # auto-generated project CLI entry point (executable)
+ cache/ # default cache directory
+ config/ # config file direcotry
- cli-config.php # auto-generated Doctrine CLI config file
- config.yml # auto-generated configuration YAML file
- routes.yml # auto-generated routing YAML file
- services.yml # auto-generated service container (to be parsed by symfony/di)
+ src/ # default source code (class files) directory
+ Controllers/ # namespace for controller classes
- DemoController.php # as the name tells, a demo controller
+ Database/ # namespace for db classes
- TestProjectDatabase.php # class which provides access to EntityManager and DBAL connection
- TestProject.php # base class for the project, extending SlimApp class
- TestProjectConfiguration.php # configuration definition class for config/config.yml
+ templates/ # default Twig template base directory
+ vendor/ # composer components directory
+ web/ # web entry directory
- front.php # entry file for HTTP Kernel
- bootstrap.php # bootstrap file
- composer.json # composer config file
- composer.lock # composer lock file
配置
SlimApp的基本配置文件是config.yml
,位于config
目录下。这是一个YAML文件,可以解释为PHP中的数组。以下是自动生成的配置文件的默认内容
# config.yml is_debug: true # is application in debug mode dir: # directory settings log: /data/logs/test-project # logging dir data: /data/test-project # data dir cache: /project-root/cache # cache dir template: /project-root/templates # template dir db: # database settings host: localhost # db host port: 3306 # db port user: test_project # db user password: test-project # db user password dbname: test_project # db name memcached: # cache settings host: localhost # memcached host port: 11211 # memcached port
config.yml
文件是严格解析的,这意味着在此文件中定义的所有值都应该符合配置定义。SlimApp利用symfony/config来支持配置定义和解析配置文件。在src/
目录下有一个自动生成的配置定义类。
引导
让我们首先看一下位于PROJECT_DIR
下的bootstrap.php
文件,以开始使用启用SlimApp的应用程序
<?php use Minhao\TestProject\TestProject; use Minhao\TestProject\TestProjectConfiguration; require_once __DIR__ . "/vendor/autoload.php"; define('PROJECT_DIR', __DIR__); /** @var TestProject $app */ $app = TestProject::app(); $app->init(__DIR__ . "/config", new TestProjectConfiguration(), __DIR__ . "/cache/config"); return $app;
以下是一些需要注意的事项
- 在这个文件中执行composer组件自动加载
- 配置定义是即时实例化的,使用自动生成的配置定义类
TestProjectConfiguration
- 引导文件返回一个类型为
TestProject
的对象,它是SlimApp
的扩展
参考配置值
有了TestProject
实例(因此是SlimApp
的实例),我们可以通过两种略有不同的方式访问配置值
通过 配置键 获取值
<?php use Oasis\SlimApp\SlimApp; use Oasis\Mlib\Utils\DataProviderInterface; /** @var SlimApp $app */ $isDebug = $app->getMandatoryConfig('is_debug', DataProviderInterface::BOOL_TYPE); $logDir = $app->getMandatoryConfig('dir.log', DataProviderInterface::STRING_TYPE); $nonExistingConfig = $app->getMandatoryConfig('non_existing_config'); // will throw $port = $app->getOptionalConfig('db.port', DataProviderInterface::INT_TYPE, 3306); $nonExistingConfig = $app->getOptionalConfig('non_existing_config'); // will return null
注意:层次配置键可以通过点"."连接
通过 参数键 获取值
<?php use Oasis\SlimApp\SlimApp; use Oasis\Mlib\Utils\DataProviderInterface; /** @var SlimApp $app */ $isDebug = $app->getParameter('app.is_debug'); $dbPort = $app->getParameter('app.db.port'); $nonExistingConfig = $app->getParameter('app.non_existing_config'); // will throw
与第一种方法相比,参数键仅在配置键之前添加"app."前缀。此外,所有参数键都必须存在,否则在访问时将抛出异常。
在实际应用中,我们建议使用参数键,因为它与在容器定义和twig模板中访问参数的方式一致。另一方面,当使用配置键时,自动类型检查能力有时是一个有用的优点。
服务容器
SlimApp大量使用依赖注入设计模式。内部,它使用symfony/dependency-injection组件来实现服务容器。
存在一个位于 config
目录下的集中式服务容器定义文件,格式为 YAML。该文件名为 services.yml
,以下是一个示例。
# services.yml imports: - { resource: "external_definition1.yml" } - { resource: "external_definition2.yml" } parameters: default.namespace: - Oasis\Mlib\ - Minhao\TestProject\ services: app: properties: logging: path: '%app.dir.log%' level: debug cli: name: test-project version: '0.1' http: cache_dir: '%app.dir.cache%' routing: path: '%app.dir.config%/routes.yml' namespaces: - Minhao\TestProject\ - Minhao\TestProject\Controllers\ twig: template_dir: '%app.dir.template%' globals: app: '@app' injected_args: - '@entity_manager' memcached: class: Memcached calls: - - addServer - - '%app.memcached.host%' - '%app.memcached.port%' entity_manager: class: Doctrine\ORM\EntityManager factory: - Minhao\TestProject\Database\TestProjectDatabase - getEntityManager
常见的 services.yml
文件包含三个部分
- 导入:这是导入其他服务定义文件的地方。借助导入功能,我们可以将大型服务定义文件分解成更小、更有意义的部分。
- 参数:这是一个键值对数组。这里定义的所有参数,以及通过使用它们的相应 参数键 在
config.yml
中定义的参数,都可以使用 "%%" 符号进行解引用,例如 '%app.memcached.host%'。 - 服务:这是服务的实际定义。服务是一个键,用于引用可注入的变量。服务可以在其他服务中引用,使用 "@" 符号,例如 '%entity_manager'。
服务描述
服务的定义方式值得更详细的解释。描述(在服务键下允许的属性)可以分为 3 个阶段
- 构建阶段
- 设置阶段
- 装饰阶段
构建阶段
首先,任何服务都需要有一个类型,这通过 class
属性来描述。
注意 类名必须是完全限定的,除非在参数 '%default.namespace%' 中可以找到前缀命名空间。
定义了 class
后,我们需要访问对象。有两种方式可以获取服务对象
- 通过使用构造函数实例化
- 或者通过使用工厂类(或工厂对象)来获取服务
services: object.constructed: class: Minhao\TestProject\User arguments: - "John Smith" # name - 25 # age object.factory.provided: class: Minhao\TestProject\User factory: [UserProvider, getUser] # factory class, factory method arguments: - 250008 # student ID
设置阶段
服务对象定义后,我们还可以修改对象,如下所示
services: object.modified: class: Minhao\TestProject\User arguments: - "John Smith" # name - 25 # age properties: tel: "1234567890" # accessed as public property age: 40 # accessed as public property, overrides constructor calls: - [setSupervisor, "@another.user"] # method and arguments
正如你所看到的,我们可以通过访问其属性或调用对象上的方法来进一步修改服务。
注意 与构建阶段相同,设置阶段中定义的所有属性将仅在构建阶段之后应用一次。
装饰阶段
还有更多强大的技术可以描述服务。尽管它们在实践中的应用并不广泛,但你可能仍然会对它们感兴趣。请参阅 Symfony 官方网站上的 指南 以了解更多信息。
定义 "@app" 服务
在 services.yml
中,必须详细描述一个且只有一个特殊服务,即 "app" 服务。
"app" 服务的构建阶段是自动完成的,需要很少的关注。区分每个应用程序的是 properties
属性
services: app: properties: logging: path: %app.dir.log% level: debug handlers: # array extra monolog hanlders - "@log.handler.email" cli: name: Slim App Console version: 1.1 commands: # array of command object - '@cli.command.dummy' http: # http bootstrap config
日志记录
SlimApp 使用 oasis/logging 作为日志工具。 oasis/logging 提供了一个即插即用的 PSR-3 兼容的日志解决方案,该解决方案建立在 monolog 之上。
默认情况下,SlimApp 会安装两个日志处理器
- 本地文件日志处理器,根据配置的日志级别将日志流到本地文件系统
- 本地文件错误处理器,仅在发生错误时(即触发 error 或更高级别的日志)将日志保存到本地文件系统
此外,对于在命令行上运行的应用程序,还会安装一个额外的控制台日志处理器。控制台日志处理器将直接写入 STDERR,并启用 ANSI 颜色 装饰。
在定义 "@app" 服务时,可以使用以下属性来设置 logging
属性:
HTTP 内核
记得我们声称 SlimApp 是一个适用于 web 和控制台开发的微框架吗?现在是时候了解 SlimApp 如何以简单而强大的方式提供构建 web 应用程序的能力了。
SlimApp 使用 oasis/http 作为其 HTTP 内核实现。 oasis/http 是广泛使用的 Silex 框架的扩展,并提供了一个严格实现 Symfony\Component\HttpKernel\HttpKernelInterface
的内核定义。
在 oasis/http 中已经很好地记录了如何引导 HTTP 内核。所以这里我们要介绍的是更简单的,即如何在服务定义中注入引导配置。
对于 "@app" 服务有一个属性,http
,它将被传递到 oasis/http 作为引导配置。http
的值必须是一个符合 oasis/http 标准 的数组。以下是一个示例配置:
services: app: properties: http: routing: path: %app.dir.config%/routes.yml namespaces: - Oasis\SlimApp\Ut\ error_handlers: '@http.error_handler' view_handlers: '@http.view_handler' cors: - path: /cors/* origins: "*"
配置无误后,我们可以像在自动生成的 front.php
文件中展示的那样使用 HTTP 内核。
<?php use Minhao\TestProject\TestProject; /** @var TestProject $app */ $app = require_once __DIR__ . "/../bootstrap.php"; $app->getHttpKernel()->run();
命令行界面
正如讨论的那样,SlimApp 不仅适用于 web 应用程序。它还提供了一个功能丰富的 CLI 框架。其底层实现大量使用了 symfony/console 组件。尽管使用 SlimApp 的基本 CLI 功能不需要对 symfony/console 有全面的知识,但如果您想扩展框架或使用一些高级功能,建议阅读 symfony 文档。
首先,让我们看看 "@app" 服务的 cli
属性。
ervices: app: properties: cli: name: Slim App Console version: 1.1 commands: # array of command object - '@cli.command.dummy'
可以设置 3 个属性:
- name:控制台应用程序的名称,在请求信息时使用(如 --help)
- version:控制台应用程序的版本,与 name 属性一起使用
- commands:应用程序特定命令的数组。命令对象也必须是类型为
Symfony\Component\Console\Command\Command
的定义服务。
控制台应用程序可以从自动生成的入口脚本 PROJECT_DIR/bin/.php 启动。
./bin/test-project.php <command>
有一个必填的 command 参数,用于确定要调用哪个 Command
对象。在 command 参数之后的所有内容都将被解释为输入参数和选项。
注意:还可以通过在控制台入口脚本中调用 addCommands()
方法将支持的命令注入 CLI,这可能更方便(尤其是在具有自动完成功能的 IDE 中)。
<?php use Minhao\TestProject\TestProject; /** @var TestProject $app */ $app = require_once __DIR__ . "/../bootstrap.php"; $console = $app->getConsoleApplication(); $console->addCommands( [ new MyCustomCommandOne(), new MyCustomCommandTwo(), ] ); $console->run();
编写自己的命令
要创建自己的命令,您可以从扩展 Symfony\Component\Console\Command\Command
类并重写至少 configure()
方法和 execute()
方法开始。
<?php namespace Minhao\TestProject\Console\Commands; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class MyCustomCommandOne extends Command { protected function configure() { parent::configure(); $this->setName('custom:command:one') ->setDescription("Say hello world!"); } protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("Hello World!"); } }
注意:命令被放置在项目根命名空间下的
Console\Commands\
命名空间中。这是 SlimApp 的一个约定,建议遵循。
使用输入参数
在大多数实际场景中,没有参数的命令是没有用的。我们可以让命令接受输入参数。
注意:请注意命令行参数和命令输入参数之间的区别。当我们用shell执行一个命令时,shell会将整个输入行分割成由空格分隔的命令行参数。当我们执行CLI命令时,第一个命令行参数($arg[0])是入口脚本名,第二个($arg[1])必须是命令名。之后,任何不以连字符('-')开头的额外命令行参数都被认为是输入参数(除了选项值,它跟在需要值的输入选项后面)。
要使您的命令能够接受输入参数,您可以使用addArgument()
方法声明您期望的参数,您可以使用传递给execut()
的$input
上的getArgument()
方法来读取参数
<?php // namespace imports omitted ... class MyCustomCommandOne extends Command { protected function configure() { parent::configure(); $this->setName('custom:command:one') ->setDescription("Say hello world!"); $this->addArgument( 'name', InputArgument::REQUIRED, "give your name here" ); } protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('name'); $output->writeln('Hello, ' . $name . '!'); } }
运行测试命令将输出
$ ./bin/test-project.php custom:command:one John
Hello, John!
注意:您可能期望有多个参数。但是,您只能将可选参数放在列表的末尾。为了更清晰,在可选参数后面不能有任何必需参数。
使用输入选项
输入选项是以一个或两个连字符开头的命令行参数。正如“选项”这个名字所暗示的,输入选项总是可选的。输入选项名有两种不同的形式:长选项名和短选项名。长选项名以两个连字符("--”)开头,每个选项都是强制性的。短选项名以单个连字符("-”)开头,是可选的。
此外,还有一些输入选项需要附加值。这些选项值的设置方式有两种
- 直接跟在选项后面的命令行参数
$ ./bin/test-project.php custom:command:one John -m question
- 在长选项名后面使用等号
$ ./bin/test-project.php custom:command:one John --mood=question
要声明和使用输入选项,请阅读下面的示例代码
<?php // namespace imports omitted ... class MyCustomCommandOne extends Command { protected function configure() { parent::configure(); $this->setName('custom:command:one') ->setDescription("Say hello world!"); $this->addArgument( 'name', InputArgument::REQUIRED, "give your name here" ); $this->addOption( 'mood', 'm', InputOption::VALUE_REQUIRED ); } protected function execute(InputInterface $input, OutputInterface $output) { $name = $input->getArgument('name'); $mood = $input->getOption('mood'); $sign = ($mood == "question") ? "?" : "!"; $output->writeln('Hello, ' . $name . '!'); } }
执行命令的输出如下
$ ./bin/test-project.php custom:command:one John --mood=question
Hello, John?
守护进程哨兵
在实际应用中,一个项目可以有一个预定的执行计划来执行多个命令。一些命令需要在给定的时间间隔内执行,一些需要并行运行多个实例,一些需要在执行失败时自动发送警报,等等。SlimApp提供了一个非常有用的功能,称为守护进程哨兵,专门用来解决这些问题。
守护进程哨兵本身也是一个命令。您的应用程序应该扩展Oasis\SlimApp\SentinelCommand\AbstractDaemonSentinelCommand
以拥有您的命令类
<?php namespace Minhao\TestProject\Console\Commands; use Oasis\SlimApp\SentinelCommand\AbstractDaemonSentinelCommand; class TestSentinelCommand extends AbstractDaemonSentinelCommand { protected function configure() { parent::configure(); $this->setName('test:daemon'); } }
当执行时,命令期望一个配置文件作为其第一个参数。文件的格式应该是YAML,例如以下内容
commands: dummy: # name of the daemon, informative only, use any name meaningful # command name name: dummy:job # command line arguments to pass to the command args: a: %app.name% --tt: true --idx: $PARALLEL_INDEX -vvv: # whether to run in parallel, and if yes, how many parallel: 3 # run only once? if not, command will restart upon previous execution ends once: false # alert on abnormal exit (exit != 0) alert: false # interval: minimum number of seconds between last end and next start interval: 2 # frequency: minimum seconds between two start frequency: 5 # frequency_fixed: default to false, if enabled, commands will start at fixed frequency, no matter if the previous run has finished or not frequency_fixed: false
注意:所有配置值都可以在命令的args设置中使用"%key-to-config-value%"的格式
注意:$PARALLEL_INDEX是args中的一个特殊变量,表示在并行执行时的命令索引。索引从0开始。