danc0 / gimliduck-php
GimliDuck 是一个适应性强的微型 PHP 框架,尽量不干扰你的工作。
Requires
- php: >=8.1
- latte/latte: >=3.0
Requires (Dev)
- phpstan/phpstan: >=1.8
- phpunit/php-code-coverage: >=9.2
- phpunit/phpunit: >=11
- squizlabs/php_codesniffer: >=3.7
- dev-master
- v0.13.5
- v0.13.4
- v0.13.3
- v0.13.2
- v0.13.1
- v0.13.0
- v0.12.2
- v0.12.1
- v0.12.0
- v0.11.6
- v0.11.5
- v0.11.4
- v0.11.3
- v0.11.2
- v0.11.1
- v0.11.0
- v0.10.4
- v0.10.3
- v0.10.2
- v0.10.1
- v0.10.0
- v0.9.3
- v0.9.2
- v0.9.1
- v0.9.0
- v0.8.3
- v0.8.2
- v0.8.1
- v0.8.0
- v0.7.1
- v0.7.0
- v0.6.7
- v0.6.6
- v0.6.5
- v0.6.4
- v0.6.3
- v0.6.2
- v0.6.1
- v0.6.0
- v0.5.1
- v0.5.0
- v0.4.1
- v0.4.0
- v0.3.6
- v0.3.5
- v0.3.4
- v0.3.3
- v0.3.2
- 0.3.1
- 0.3.0
- dev-gimliduck-6
- dev-gimli-phpcs
This package is auto-updated.
Last update: 2024-10-03 05:30:41 UTC
README
一个适应性强的微型 PHP 框架,尽量不干扰你的工作。
这是一个仍在进行中的项目,使用时请自担风险...
死亡的确定性。成功的小概率。我们还在等什么?
安装
composer require danc0/gimliduck-php
使用以下命令创建一个骨架项目: composer create-project danc0/gimli-skeleton
使用以下命令添加 devtools: composer require --dev danc0/gimliduck-devtools
创建一个类似以下内容的 .htaccess
文件,以便将请求指向您的 index.php
文件
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
使用方法
创建 GimliDuck 应用程序非常简单
declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use Gimli\Application; use Gimli\Router\Route; $App = Application::create(__DIR__, $_SERVER); Route::get('/', function(){ echo "Hello World"; }); $App->run();
这就是您开始所需的所有内容。您可以添加更多内容,例如模板引擎、配置文件等,但您不必这么做。
一个更复杂的示例
<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use Gimli\Application; use App\Core\Config; use App\Core\Cache; define('APP_ROOT', __DIR__); $App = Application::create(APP_ROOT, $_SERVER); // set up your config and add it to the Application $config_file = parse_ini_file(APP_ROOT . '/App/Core/config.ini', true); $App->Config = $App->Injector->resolveFresh(Config::class, ['config' => $config_file]); // Register a cache class with the Injector $App->Injector->register(Cache::class, Cache::getCache($App->Config->admin_cache)); // Run Application $App->run();
当创建时,Application 类也会注册基本事件处理程序和 Session 类。另外,如果您的配置包含 enable_latte
,则 Latte 模板引擎将使用配置中的 template_base_dir
值作为模板目录添加到 Application 实例中。
声明路由
默认情况下,Gimli 会要求加载 App/Routes
目录下的任何文件。您可以通过在配置文件中将 autoload_routes
设置为 false
来禁用此功能。您可以通过在配置文件中将 route_directory
的值来更改目录。您还可以使用以下方法加载额外的路由文件
// Load routes from a file(s) $App->loadRouteFiles([ 'App/routes/web.php', ]);
您可以在路由回调中做几件事情...传递一个字符串、一个可调用对象或一个数组。
Route::get('/', function(){ echo "Hello World" }); // Single action controller, must use __invoke method Route::get('/', Home_Controller::class); // cli routes are single action Job classes Route::cli('build-cache', Cache_Job::class); Route::get('/', Home_Controller::class . '@homePage'); Route::get('/', [Home_Controller::class, 'homePage']);
这些都可以,具体取决于您如何操作。
如果需要额外的防御,您可以添加中间件
Route::get('/', [Home_Controller::class, 'homePage'])->addMiddleware(Logged_In_Middleware::class);
这应该是一个实现了 Gimli\Middleware\Middleware_Interface
的类,该接口需要一个返回 Gimli\Middleware\Middleware_Response
的 process
方法。中间件可以访问 Application 实例,包括注入器以及您决定设置的任何其他内容。
您还可以添加组,定义一个默认的路由文件,以及加载额外的路由文件以帮助组织路由。
您的路由也可以包含符合以下模式的可变参数
protected array $patterns = [ ':all' => "([^/]+)", ':alpha' => "([A-Za-z_-]+)", ':alphanumeric' => "([\w-]+)", ':integer' => "([0-9_-]+)", ':numeric' => "([0-9_-.]+)", ':id' => "([0-9_-]+)", ':slug' => "([A-Za-z0-9_-]+)", ];
您需要使用 #
符号在路由定义中添加它们的变量名称。
Route::get('/user/:integer#id', [User_Controller::class, 'getUser']);
此变量名称传递给路由器,并将其设置为控制器方法的依赖项。您应该在控制器方法中使用定义的变量名称作为参数。值将根据可用的 settype
类型转换为类型,可能的类型
integer or int
float or double
string
array
object
boolean or bool
示例控制器方法
public function getUser(Response $Response, int $id): Response { // do something with $id }
控制器应返回一个 Gimli\Http\Response
对象。有一些辅助方法可以返回格式化的 Response
对象,以帮助减少一些条件逻辑。
response
基本响应redirect
重定向响应redirect_on_success
如果响应成功则重定向redirect_on_failure
如果响应不成功则重定向json_response
JSON 响应
作业文件也提供了以下参数 subcommand
、options
和 flags
。options
参数是一个包含名称和值的数组数组。 flags
参数是包含给定标志的数组。如果提供了子命令,则 subcommand
参数仅是一个字符串。
依赖注入
您可以使用内置的注入器来绑定或注册依赖项。您还可以从注入器中解析依赖项。您可以将任何需要的内容添加到注入器中,并通过 Application
实例在您的应用程序中访问它。
内置的注入器会自动连接类并按需解析依赖项。如果您需要在返回类之前进行一些设置或注册已创建的对象,您还可以将一个类绑定到一个闭包中。以下示例展示了从 Router 类解析的单个动作控制器。构造函数的参数是通过注入器解析的。
<?php declare(strict_types=1); namespace App\Controllers; use App\Logic\Dashboard_Logic; use Gimli\Http\Response; use Gimli\Application; use Gimli\View\Latte_Engine; class Dashboard_Landing_Controller { /** * Constructor * * @param Application $Application */ public function __construct( public Application $Application, protected Dashboard_Logic $Dashboard_Logic, protected Latte_Engine $View ){ // } /** * Single action controller call * * @return Response */ public function __invoke(Response $Response): Response { $template_data = $this->Dashboard_Logic->getTemplateData(); return $Response->setResponse($this->View->render('dashboard/dashboard.latte', $template_data)); } }
当路由分发方法时,注入器也会解析方法参数。
还有一些注入器辅助方法可以减少一些内联代码。通常,如果您想要内联注入一个类,可以使用 $this->Application->Injector->resolve(Some_Class::class)
或 Application::get()->Injector->resolve(Some_Class::class)
。resolve
和 resolve_fresh
方法可用于减少内联代码。
数据库
有一个基本的 PDO 包装器 Database
以及一个 Pdo_Manager
类,您可以使用它来管理数据库查询。Pdo_Manager
类返回一个 PDO
实例,可以用于直接运行查询。Database
类是 Pdo_Manager
类的包装器,提供了一些基本的查询方法。还有一个非常基本的 Model
基类和一些用于 Database
的辅助方法,如其他地方,这些方法处理依赖注入并调用注入的 Database
类的方法。辅助方法包括:
fetch_column
fetch_row
fetch_all
row_exists
模型种子器
有一个基本的种子器类,可以用于对您的数据库进行种子。这依赖于在模型类中放置的属性,以指导 Seeder_Factory
如何创建数据。
<?php declare(strict_types=1); namespace Gimli\Database; use Gimli\Database\Model; use Gimli\Database\Seed; class User_Model extends Model { /** * @var string $table_name */ protected string $table_name = 'users'; /** * ID * * @var int $id */ public $id; /** * Unique_Id * * @var string $unique_id */ #[Seed(type: 'unique_id', args: ['length' => 12])] public $unique_id; /** * Username * * @var string $username */ #[Seed(type: 'username')] public $username; /** * Email * * @var string $email */ #[Seed(type: 'email')] public $email; /** * Password * * @var string $password */ #[Seed(type: 'password')] public $password; /** * Is_Active * * @var int $is_active */ #[Seed(type: 'tiny_int')] public $is_active; /** * First Name * * @var string $first_name */ #[Seed(type: 'first_name')] public $first_name; /** * Last Name * * @var string $last_name */ #[Seed(type: 'last_name')] public $last_name; /** * Status * * @var int $status */ #[Seed(type: 'one_of', args: [0,1])] public $status; /** * Created_At * * @var string $created_at */ #[Seed(type: 'date', args: ['format' => 'Y-m-d H:i:s', 'min' => '2021-01-01', 'max' => '2021-04-01 00:00:00'])] public $created_at; /** * Updated_At * * @var string $updated_at */ #[Seed(type: 'date', args: ['format' => 'Y-m-d H:i:s', 'min' => '2021-04-01 00:02:00'])] public $updated_at; /** * bio * * @var string $about */ #[Seed(type: 'paragraph', args: ['count' => 1])] public $about; }
然后可以使用以下代码对数据库进行种子:
Seeder_Factory::make(User_Model::class) ->seed(123) ->count(1) ->create();
除了创建,您还可以调用 getSeededData
来获取将插入数据库的数据。这在测试或手动加载模型而不保存它时很有用。您还可以传递一个回调方法,该方法将接收初始模型的数据。这有助于种子相关数据。回调应返回一个 Seeder_Factory
实例的数组。
Seeder_Factory::make(User_Model::class) ->seed(123) ->count(1) ->callback(function($data) { return [ Seeder_Factory::make(User_Hobby_Model::class)->with(['user_id' => $data['id']]), Seeder_Factory::make(User_Group_Model::class)->with(['user_id' => $data['id']]), ] }) ->create();
传递的种子确保每次运行种子器时数据都保持一致,从而产生可重复的数据集。Seeder_Factory
类有一个 getRandomSeed
方法,该方法将返回一个随机种子值。这对于创建不需要重复的随机数据很有用,或者生成可以复制并使用的随机种子。
配置辅助工具
还有一些配置辅助工具
get_config
获取整个配置数组get_config_value
从配置数组中获取特定值config_has
检查配置数组中是否存在键