ricardoper/slim4-twig-skeleton

一个更好的Slim Framework 4骨架,带有Twig,提供合理的文件夹结构,其中一切都可以自定义

v2.2.0 2020-05-25 11:42 UTC

This package is auto-updated.

Last update: 2024-08-25 21:53:04 UTC


README

一个超级有组织(具有合理的文件夹结构)并且非常可定制的Slim Framework v4骨架,带有Twig视图。用它来快速开始新项目。

注意:如果您想要这个没有Twig的骨架,请访问:https://github.com/ricardoper/slim4-skeleton

此项目使用PHP Composer 来快速安装,无需任何麻烦。

  • PHP >= 7.2
  • 易于配置的自定义
    • 视图
    • 记录器
    • 路由
    • 处理器
    • 中间件
    • 配置
    • 服务提供者
    • 响应发射器
    • 错误处理器
    • 关闭处理器
  • Twig 视图
  • 会话
  • 控制器
  • 全局助手
  • PSR-3 用于记录
  • 使用 PHP dotenv 的环境变量
  • Pimple 作为依赖注入容器
  • ddumper 用于开发(基于 Symfony VarDumper
  • 更好的错误处理器(HTML、JSON、XML、纯文本 - 接受 / 内容类型)
  • Medoo 数据库框架(MySQL、PostgreSQL、SQLite、MS SQL Server、...)

注意:

  • Medoo 是可选的,默认情况下未启用。您可以使用其他库作为服务提供者。如果您想使用此库,请不要忘记安装所需的PDO扩展。

目录

如何安装

从您想安装新Slim Framework v4骨架和Twig视图的目录运行此命令。

composer create-project ricardoper/slim4-twig-skeleton [my-app-name]

注意:

  • [my-app-name] 替换为您新应用的所需目录名。
  • 确保 storage/ 可供Web写入。
  • 将您的虚拟主机文档根指向新应用的 public/ 目录。

最相关的文件夹

  • /app : 应用程序 代码(App 命名空间 - PSR-4
    • ./Controllers : 接受输入并将其转换为模型命令。在此处添加您的 控制器
    • ./Emitters : 根据环境发射响应,包括状态行、头和消息体。在此处添加您的 响应发射器
    • ./Handlers : 处理应用程序的指定行为。在此处添加您的 处理器
    • ./Middlewares : 提供一个方便的机制来过滤进入应用程序的HTTP请求。在此处添加您的 中间件
    • ./Models : 管理应用程序的数据、逻辑和规则。在此处添加您的 模型
    • ./Routes : 将HTTP请求映射到请求处理器(控制器)。在这里添加您的 Routes
    • ./Services : 定义绑定和注入依赖。在这里添加您的 Service Providers
    • ./Views : 任何信息表示,如图表、图表或表格。在这里添加您的 Twig Views
  • /configs : 在这里添加/修改您的 Configurations
  • /public : 在这里添加您的 Assets 文件。

全局助手

  • env(string $variable, string $default) - 返回 环境变量(使用DotEnv)
  • app() - 返回 App 实例
  • container(string $name) - 从 Container 返回绑定和注入依赖
  • configs(string $variable, string $default) - 返回 Configs 数据
  • base_path(string $path) - 返回 基础路径 位置
  • app_path(string $path) - 返回 app路径 位置
  • configs_path(string $path) - 返回 configs路径 位置
  • public_path(string $path) - 返回 public路径 位置
  • storage_path(string $path) - 返回 storage路径 位置

仅限开发的全局助手

  • d($var1, $var2, ...) - 默认以折叠模式导出变量
  • ddd($var1, $var2, ...) - 默认以折叠模式导出并退出变量
  • de($var1, $var2, ...) - 默认以展开模式导出变量
  • dde($var1, $var2, ...) - 默认以展开模式导出并退出变量

配置

您可以添加尽可能多的配置文件(/configs)。这些文件将在容器中根据所选环境 自动预加载并合并

如果您有一个名为 "sandbox" 的环境,并且只想为此环境覆盖一些配置,您需要在 /configs 中创建一个名为 "sandbox" 的子文件夹。例如 /configs/sandbox。然后创建一个包含您需要替换的配置、相应键和值的文件。

/configs/logger.php

return [

    'name' => 'app',

    'maxFiles' => 7,

];

/configs/local/logger.php

return [

    'name' => 'app-local',

];

环境 name 的结果

  • prod : 'app'
  • sandbox : 'app'
  • local : 'app-local'
  • testing : 'app'

注意:您可以在本框架中查看 local 环境的示例。

配置点表示法

您可以使用 点表示法 从配置中获取值。

/configs/example.php

return [

    'types' => [
        'mysql' => [
            'host' => 'localhost',
            'port' => '3306',
        ],
        'postgre' => [
            'host' => 'localhost',
            'port' => '3306',
        ],
    ],

];

如果您想获取MySQL类型的 host

$this->getConfigs('example.types.mysql.host')  => 'localhost'

configs('example.types.mysql.host') => 'localhost'

container('configs')->get('example.types.mysql.host') => 'localhost'

路由

将HTTP请求映射到请求处理器(闭包或控制器)。

您可以添加尽可能多的路由文件(/app/Routes),但是您需要在 /apps/Routes/app.php 文件中启用这些文件。

您可以按自己的喜好组织这些路由。有一个小示例,您可以查看如何组织这些文件。

use App\Controllers\Demo\AddressesController;
use App\Controllers\Demo\HelloController;
use App\Controllers\Demo\HomeController;
use Slim\App;

/**
 * @var $app App
 */

$app->get('/', [(new HomeController()), 'index']);

$app->get('/flash', [(new HomeController()), 'flash']);

$app->get('/dump', [(new HomeController()), 'dump']);

$app->get('/hello/{name}', [(new HelloController()), 'index'])->setName('namedRoute');

$app->get('/addresses', [(new AddressesController()), 'list']);

$app->get('/addresses/pdo', [(new AddressesController()), 'pdo']);

控制器

接受输入并将其转换为模型的命令。

您可以在一个干净的方式中添加尽可能多的 Controllers/app/Controllers)。

添加您的 Controller 后,您可以在您的 Routes 中启用或禁用它。

注意:要使用助手,必须使用位于 \App\Kernel\AbstractsControllerAbstract 扩展 Controllers

use App\Kernel\Abstracts\ControllerAbstract;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;

class HomeController extends ControllerAbstract
{

    /**
     * Index Action
     *
     * @param Request $request
     * @param Response $response
     * @return Response
     * @throws LoaderError
     * @throws RuntimeError
     * @throws SyntaxError
     */
    public function index(Request $request, Response $response): Response
    {
        unset($request, $response);

        return $this->render('Demo/Home/index.twig');
    }

控制器助手

  • getApp() - 返回 App 对象
  • getContainer(string $name) - 返回 App Container
  • getConfigs(string $name) - 返回 App Configs
  • getService(string $service) - 通过名称从容器中返回 ServiceProvider
  • getRequest() - 返回 HTTP 请求
  • getResponse() - 返回 HTTP 响应
  • setEmitter(string $name, string $emitter) : 设置新的 响应发射器
  • getView() - 返回 Twig 对象
  • render(string $template, array $data, bool $sendHeaders) - 渲染 Twig 视图

闪存消息助手

  • getFlash() - 返回 Flash Messages 对象
  • setFlashMessage(string $key, $message) - 设置 Flash Message
  • hasFlashMessage(string $key) - 验证Flash Messages的键是否存在
  • getFlashMessages(string $key) - 获取一个或所有Flash Messages
  • getFlashFirstFMessage(string $key, $default) - 获取键的第一个Flash Messages

视图

您可以以整洁的方式添加任意多的视图(位于/app/Views)。

您也可以根据需要组织文件夹结构。

我们建议在您的文件中使用twig扩展以实现代码高亮。

视图助手

  • url_for() - 返回给定路由的URL。例如:/hello/world
  • full_url_for() - 返回给定路由的URL。例如:http://www.example.com/hello/world
  • is_current_url() - 如果提供的路由名称和参数对当前路径有效,则返回true
  • current_url() - 返回当前路径,包含或不包含查询字符串
  • get_uri() - 从传入的ServerRequestInterface对象返回UriInterface对象
  • base_path() - 返回基本路径

您可以使用url_for生成到任何Slim应用程序命名路由的完整URL,并使用is_current_url确定是否需要将链接标记为活动状态,如示例Twig模板所示

{% extends "layout.html" %}

{% block body %}
<h1>User List</h1>
<ul>
    <li><a href="{{ url_for('profile', { 'name': 'josh' }) }}" {% if is_current_url('profile', { 'name': 'josh' }) %}class="active"{% endif %}>Josh</a></li>
    <li><a href="{{ url_for('profile', { 'name': 'andrew' }) }}">Andrew</a></li>
</ul>
{% endblock %}

中间件

提供一种方便的机制来过滤进入您应用程序的HTTP请求。

您可以以整洁的方式添加任意多的中间件(位于/app/Middlewares)。

添加您的中间件后,您可以在configs/middlewares.php配置文件中启用或禁用它。

注意中间件必须遵循位于\Psr\Http\Message中的MiddlewareInterface

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\MiddlewareInterface as Middleware;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

class ExampleMiddleware implements Middleware
{

    /**
     * Process an incoming server request.
     *
     * Processes an incoming server request in order to produce a response.
     * If unable to produce the response itself, it may delegate to the provided
     * request handler to do so.
     *
     * @param Request $request
     * @param RequestHandler $handler
     * @return Response
     */
    public function process(Request $request, RequestHandler $handler): Response
    {
        $response = $handler->handle($request);

        $response = $response->withHeader('X-Example', 'Middleware');

        return $response;
    }
}

configs/middlewares.php中启用

use App\Middlewares\Demo\ExampleMiddleware;

return [

    'example' => ExampleMiddleware::class,

];

响应发射器

根据环境发出响应,包括状态行、头信息和消息体

您可以以整洁的方式添加任意多的响应发射器(位于/app/Emitters)。

添加您的响应发射器后,您可以在configs/emitters.php配置文件中全局启用或禁用它,或者您可以在控制器中添加它以用于特定的操作。

注意响应发射器必须遵循位于\App\Kernel\Interfaces中的ResponseEmitterInterface

use App\Kernel\Interfaces\ResponseEmitterInterface;
use Psr\Http\Message\ResponseInterface;

class JsonResponseEmitter implements ResponseEmitterInterface
{

    /**
     * Send the response to the client
     *
     * @param ResponseInterface $response
     * @return ResponseInterface
     */
    public function emit(ResponseInterface $response): ResponseInterface
    {
        $response = $response
            ->withHeader('Content-Type', 'application/json; charset=UTF-8');

        return $response;
    }
}

configs/emitters.php中启用

use App\Emitters\JsonResponseEmitter;

return [

    'json' => JsonResponseEmitter::class,

];

模型

管理应用程序的数据、逻辑和规则。

您可以以整洁的方式添加任意多的模型(位于/app/Models)。

添加您的模型后,您可以在控制器中使用它,例如。

注意:要使用助手,必须使用位于\App\Kernel\Abstracts中的ModelAbstract扩展模型

use App\Kernel\Abstracts\ModelAbstract;
use PDO;

class AddressesModel extends ModelAbstract
{

    /**
     * Get Last Addresses with Pdo
     *
     * @param int $limit
     * @return array
     */
    public function getLastWithPdo(int $limit = 25): array
    {
        /** @var $db PDO */
        $db = $this->getDb()->pdo;

        $sql = 'SELECT `address`.`address_id`,`address`.`address`,`address`.`address2`,`address`.`district`,`city`.`city`,`address`.`postal_code`,`address`.`phone` FROM `address` ';
        $sql .= 'LEFT JOIN `city` ON `address`.`city_id` = `city`.`city_id` ';
        $sql .= 'ORDER BY `address_id` DESC LIMIT 10';

        return $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    }

模型助手

  • getApp() - 返回 App 对象
  • getContainer(string $name) - 返回 App Container
  • getConfigs(string $name) - 返回 App Configs
  • getService(string $service) - 通过名称从容器中返回 ServiceProvider
  • getRequest() - 返回 HTTP 请求
  • getResponse() - 返回 HTTP 响应
  • getDb() - 返回数据库对象

服务提供者

定义绑定并注入依赖。

您可以以整洁的方式添加任意多的服务提供者(位于/app/Services)。

添加您的服务提供者后,您可以在configs/services.php配置文件中启用或禁用它。

注意服务提供者必须遵循位于\App\Kernel\Interfaces中的ServiceProviderInterface

use App\Kernel\Interfaces\ServiceProviderInterface;
use Pimple\Container;

class ExampleServiceProvider implements ServiceProviderInterface
{

    /**
     * Service register name
     */
    public function name(): string
    {
        return 'example';
    }

    /**
     * Register new service on dependency container
     *
     * @param Container $container
     * @return mixed
     */
    public function register(Container $container)
    {
        return function (Container $c) {
            unset($c);

            return new Example();
        };
    }
}

configs/services.php中启用

use App\Services\Demo\ExampleServiceProvider;

return [

    'example' => ExampleServiceProvider::class,

];

处理器

处理应用程序指定的行为。

您可以以整洁的方式覆盖以下处理器(位于/app/Handlers

  • ErrorHandler(默认位于/app/Handlers/ErrorHandler
  • ShutdownHandler(默认位于/app/Handlers/ShutdownHandler

添加您的处理器后,您可以在configs/app.php配置文件中启用或禁用它。

use App\Handlers\ShutdownHandler;
use Slim\Handlers\ErrorHandler;

return [

    // Handlers //
    'errorHandler' => ErrorHandler::class,

    'shutdownHandler' => ShutdownHandler::class,

数据库支持

Medoo作为服务提供者内置。使用是可选的,默认不启用。

要使用Medoo启用数据库支持,您需要使用Composer添加此库/供应商

composer require catfan/medoo

安装后,您需要在configs/services.php中启用服务提供者

use App\Services\Database\DatabaseServiceProvider;

return [

    'database' => DatabaseServiceProvider::class,

];

现在您可以使用它了...

如需更多信息、文档、API参考,请访问Medoo官网:https://medoo.in/

注意:

  • 别忘了为您的数据库加载PDO扩展。例如,如果您需要MySQL,您需要安装pdo_mysql PHP扩展。
  • 您可以使用其他库作为服务提供者(MySQLi、PostgreSQL、MongoDB、Redis等的本地驱动)。

异常

您有一些异常可以直接使用,位于\App\Kernel\Exceptions中。

ConfigsException  - For Configurations Exceptions
ModelException    - For Models Exceptions
ViewException     - For ViewsExceptions

记录

默认启用日志记录,您可以在/storage/logs/app-{date}.log中查看所有输出。

您可以在/.env/configs/app.php中设置这些参数。

LOG_ERRORS |  logErrors  (bool)  - Enable/Disable logging.

LOG_ERRORS_DETAILS  |  logErrorDetails  (bool)  - Enable/disable extra details in the logging file.

LOG_TO_OUTPUT  | logToOutput  (bool)  - `true` to output the logs in console, `false` to output logs in file.

调试

默认情况下禁用调试。您可以在/.env/configs/app.php中设置这些参数。

APP_DEBUG  |  displayErrorDetails  (bool)  - Enable/disable debugging.

演示

此骨架包含一个简单的示例,您可以在这里看到所有这些功能的实际应用。

示例URL

 /               - Hello World Example.
 /flash          - Redirect with Flash Message.
 /hello/{name}   - Greet User. Replace {name} with your name.
 /addresses      - Database example with Medoo
 /addresses/pdo  - Database example with PDO from Medoo
 /dump           - See the source code of this action.

基准测试

没有什么是免费的,所以让我们比较与Slim骨架的性能损失。

机器
Intel® Core™ i5-8400 CPU @ 2.80GHz × 6
16Gb RAM
SSD

版本
Ubuntu 20.04 LTS
Docker v19.03.8
nginx 1.17.10
PHP v7.4.3
Zend OPcache启用
SIEGE 4.0.4

基准测试详情
25个并发连接
每个线程500个请求
请求之间无延迟
命令:siege -c25 -b -r500 "URL"


享受简洁性 :oP