angedelamort/php-sun-framework

另一个简单的PHP框架

v0.3.0 2020-10-08 14:33 UTC

This package is auto-updated.

Last update: 2024-09-08 23:07:54 UTC


README

另一个简单的PHP框架。

特性

  • 路由 - Slim
  • 模板化 - Twig
  • i18n(国际化)- 自定义
  • 简单用户管理 - 自定义
  • CSRF令牌 - twig
  • 渲染状态机 - 自定义
  • 缓存 - 自定义
  • 服务器端表格集成 - DataTables.net(删除?)
  • 调试栏 - DebugBar

安装

composer require "angedelamort/php-sun-framework"

运行所有测试

composer run tests

使用docker-compose

只需在命令前加上前缀

docker-compose run %composer-command%

使用

快速开始,无需过多配置。

--- index.php ---
<?php
use sunframework\SunApp;

require('autoload.php');

$app = new SunApp([
    'routes.custom' => function(Slim\App $app) {
        $app->get('/', function() {
            return "Hello World";
        });
    }
]);
$app->run()

这是简单的,但如果在index.php中放入太多代码,则扩展性不好。由于您使用composer,因此建议您结合此框架使用“psr-4”机制。我建议您快速查看示例。

--- public/index.php ---
<?php

use sunframework\SunApp;

require "../../vendor/autoload.php";

$app = new SunApp([
    'i18n.directory' => dirname(__DIR__) . '/locale',
    'view.templates' => dirname(__DIR__) . '/templates',
    'routes.controllers' => 'sample\controllers'
]);
$app->run();
--- app/controllers/HomeController.php ---
namespace sample\controllers;

use sunframework\route\IRoutable;

class HomeController implements IRoutable {
    public function registerRoute($app) {
        $app->get('/', function($request, $response, $args) {
            return $this->view->render($response, 'test.twig', [
                'user' => 'John Doe'
            ]);
        });
    }
}
--- templates/test.twig---
<!DOCTYPE html>
<html>
<body>
<h1>{{ i18n('appName') }}</h1>
<p>Hello {{ user }}.</p>
</body>
</html>

因此,这是一个简单的MVC设计。

  • "test.twig"是视图。查看twig以获取更多关于模板化的信息
  • "HomeController"是您的控制器,这是您将路由绑定到视图的地方。
  • 在这个示例中,模型更为微妙,但它是一个包含"user"的数组。它可以像这样硬编码,或者您可以在模型目录中创建一个真正的模型。

运行示例

使用docker-compose

docker-compose run composer install
docker-compose up

启动https://:9999/

文档

该框架的目的是提供一个简单的方法来使用路由和模板引擎创建php应用程序。我已经添加了一些其他功能,但我的最初想法是我不想依赖于任何复杂的东西来设置我的代码。

首先,由于我一直在使用docker,所以我使用它来开发和测试我的代码。这要简单得多,因为我不必与不同的配置文件或php/mySql/apache等版本作斗争。

其次,我通常讨厌当我想使用外部框架时,我必须将其本地化或将我的代码与框架混合,或者我必须设置一个数据库,因为框架要求这样做。

最后,我想要一个可以轻松扩展和添加功能而没有限制的东西。因此,我尽量保持技术的纯度。此外,我还添加了一些twig扩展来简化模板化。

我希望你会喜欢它。

SunApp配置

配置在文件"SunApp.php"中。

如果您希望有一个可工作的应用程序,您必须向routes.controllers添加一个命名空间,或者至少在routes.custom中设置一个自定义回调。并且为了使其工作,您必须让Web服务器知道您希望将所有路由都指向index.php。在示例文件夹中,我已经添加了一个.htaccess,或者您可以查看/phpdocker/ngnix/ngnix.conf以获取示例。

public $config = [
        'routes.controllers' => null,   // string|array<string>: Override with namespace(s) containing controllers (Must inherit from IRoutable).
        'routes.custom' => null,        // callback: If you just want to make a simple function for registering your routes.
        'view.templates' => '.',        // string|array<string>: directory where the twig templates are located.
        'view.cache' => false,          // bool: set to true to enable the cache
        'view.csrf' => false,           // enable CSRF token.
        'view.addExtension' => null,    // callback($twig): If you want to register new extension
        'session.cookie_lifetime' => 1209600,   // int: 14 days is the default.
        'i18n.directory' => null,       // string: locale directory. If null, no locale will be set.
        'i18n.default' => 'en-us',      // string: the default locale. You will need a file with this extension
        'i18n.domain' => 'default'      // string: the name of the file that will be used to find the string.
    ];

如果此文档已过时,请始终参考该文件。

控制器

待定:解释其工作方式(psr4)以及如何实现

用户权限

解释角色

模板化

使用twig(《https://twig.symfony.com.cn/doc/2.x/》)它是一个简单但功能强大的模板引擎。

我添加了一些助手(扩展)以简化某些操作。请参阅本节的其他部分以获取更多信息。

全局变量

  • user:待定
  • userRole:待定
  • csrf:待定

函数

js & css

待定:LibraryExtension::addLibrary(...)

此函数用于包含已注册的库或普通文件。目标是简化模板。

语法很简单:{{ js(param1, param2, ...) }}

示例

{{ js('jquery', 'semantic-ui') }}
{{ css('css/home.css') }}

注意:这些宏的最终目标是将文件合并在一起并在服务器端进行压缩,而不是运行单独的过程。

csrf

我创建这个是因为我们必须添加隐藏字段用于CSRF令牌。由于重复相同的代码会很烦人,所以我创建了这个小型实用程序。你可以查看下一节 CSRF 令牌,但它的使用方式如下

<form method="POST" action="action.php">
    {{ csrf() }}
    <input type="text" name="test" />
    <input type="submit" value="Submit">
</form>

CSRF 令牌

什么是 CSRF 令牌? https://en.wikipedia.org/wiki/Cross-site_request_forgery 因此,如果你使用表单进行 POST 操作,你可能想要添加这个。

如何将其添加到页面模板

生成 CSRF 令牌有两种方式

  1. 手动使用全局变量
<input type="hidden" name="{{csrf.keys.name}}" value="{{csrf.name}}">
<input type="hidden" name="{{csrf.keys.value}}" value="{{csrf.value}}">

---> will output something like: 
<input type="hidden" name="csrf_name" value="csrf5da7cd639e2e2">
<input type="hidden" name="csrf_value" value="6d7cd94be73fef2d2da0a862077ef3b2">
  1. 使用函数生成器
{{ csrf() }}

---> will output something like: 
<input type="hidden" name="csrf_name" value="csrf5da7cd639e2e2"><input type="hidden" name="csrf_value" value="6d7cd94be73fef2d2da0a862077ef3b2">
白名单

在某些情况下(例如 API),你可能想要禁用某些路由的 CSRF,因为它会自动添加到除 GET 之外的所有方法中。我已经为这种情况添加了白名单机制。

你只需实现 IWhitelistable 接口。目前它不使用任何花哨的机制,仅使用 "startsWith"。

切换

有时你想要在模板中执行切换语句。

{% switch value %}
    {% case value %}
    {% case value %}
    {% default %}
{% endswitch %}

添加新的 Twig 扩展

当框架添加 twig 扩展时,你可以在初始化应用时通过注册回调来调用。

$app = new SunApp([
    'view.addExtension' => function($view) {
        $view->addExtension(new MyExtension());
    }
]);

用户和身份验证

todo: 简单说明如何使用和覆盖

使用库/包含

在模板部分,我添加了一种在页面中包含文件的方法。原因如下

  1. 我喜欢使用 CDN 版本
  2. 在所有模板上保持相同的版本总是很复杂。
  3. 在压缩版本和标准版本之间切换可能会很烦人。

附加功能

状态机

你可能想说:“为什么需要一个新状态机?”我可能同意你的看法,因为已经有非常好的状态机了。但我想创造一些与众不同的东西。

  1. 我希望我的状态机是懒加载初始化的。由于脚本每次都会加载,我不想实例化整个状态机。
  2. 我希望创建一个面向渲染的状态机(MVC)。在这种情况下,它与控制器模型完美集成。

这不是一个高级状态机(没有层次结构)且实现非常“原始”。

为了正确理解这个想法,我建议你尝试样本“hangman”并随后检查代码。我实现了一个非常简单的游戏,但你可以轻松想象其他部分。

它是如何工作的

  1. 你使用适当的转换定义状态
  2. 使用状态初始化状态机。
  3. 调用它的 step(),它将执行具有条件的转换。
  4. 一旦发生转换,你必须处理持久性。

状态

状态包含转换。你必须继承基础类 BaseState。基础类包含许多默认值,你可以覆盖。

class FinalState extends BaseState {
    public function __construct() {
        parent::__construct();
        
        $mySimpleTransition = new Transition(NextState::name());
        $this->addTransition($mySimpleTransition);
    }
}

转换

与状态类似,如果你看到使用案例,可以创建自己的转换。与状态不同,你添加条件而不是转换。默认情况下,如果没有条件,转换始终为真。

此外,由于 不建议 在验证中更改值,我在转换的末尾添加了一个 onExecute 回调,如果结果为真。

$t = new Transition(NextState::name(), [$this, 'setLetter']);
$t->addCondition(function (StateMachineContext $context) {
    $val = intval($context->getRequest()->getParsedBodyParam('val'));
    return $val < 10;
});

因此,在这个例子中,如果 POST 参数 'val' 小于 10,转换将为真,状态机可以转到 NextState

工厂

由于在状态名称(您希望持久化的)和类之间进行映射表会很烦人,因此我为这个问题添加了一个小型工厂。和控制器一样,它基于“haydenpierce/class-finder”包。

SSP

服务器端 datatables.net

使用调试栏进行调试

在项目中,我添加了https://github.com/maximebf/php-debugbar。由于它使用twig 1.0,我不得不做一些体操才能让它工作。此外,由于它注册到monolog的方式,我不得不做一些包装。所以,如果你想使用它,以下是一些步骤。

  1. 初始化您的应用程序时,将调试栏添加到选项中
    $options = new SunAppConfig()->activateDebugBar(__DIR__ . '/generated', '/generated')->(...)
    $app = new SunApp($options);
  2. 在您的Twig模板中,您需要添加2个语句
    <!-- HEADER -->
    {{ debugBarHeader() }}
    
    <!-- END OF BODY -->
    {{ debugBarFooter() }}
  3. 通常,从这里开始工作,但如果您想使新消息被debugBar捕获,您将需要使用包装器SunLogger
    // Normal monolog stuff
    $logger = new SunLogger('name');
    $logger->info('Hello here!');
    
    // To appear in the 'Message' section
    $logger->message('Should appear in the message section');

注意:由于我不想让人们为了调试目的而四处复制文件,我在初始化调试栏时生成了给定目录的文件。但如果您开始玩它(更改一些配置),您可能需要在重新渲染之前手动删除生成的文件。

此外,jQuery已禁用。您需要手动包含它。我不想同时拥有多个版本的jQuery。由于它是用于调试目的,我认为这是一个小烦恼。