stanx/extdirect

PHP 与 Ext.Direct 集成

1.3.0 2021-04-12 19:45 UTC

This package is auto-updated.

Last update: 2024-09-13 03:44:13 UTC


README

PHP 与 Ext.Direct 集成非常简单

原作者:J. Bruni
Fork:stanx

如何使用

  1. PHP
<?php
require 'ExtDirect.php';

class Server
{
    public function date($format)
    {
        return date($format);
    }
}

ExtDirect::provide('Server', true);

在这里,“服务器”是我们希望从 JavaScript 代码中提供访问的 PHP 类。它可以是任何其他类。

  1. HTML
<script type="text/javascript" src="ext-direct.php"></script>

在这里,“ext-direct.php”指向第1项中显示的 PHP 文件。如果您想为 Ext Designer 输出 API,必须添加“?json”查询字符串,因为默认输出是javascript格式。它可以由 $default_api_output 更改。

  1. JavaScript
Ext.php.Server.date( 'Y-m-d', function(result) {
    alert('Server date is ' + result);
});

在这里,要调用 PHP “服务器”类中的“date”方法,我们在默认命名空间 Ext.php 前添加了前缀。第一个参数是 $format 参数。第二个参数是 AJAX 调用完成后将执行的 JavaScript 回调函数。这里,一个警告框显示了结果。

特性

  • 使用多个类声明 API(不仅限于单个类)
  • API urlnamespacedescriptor 设置(“ExtDirect”类在您不指定的情况下自动分配它们)
  • 两种 API 输出格式:json(用于与 Ext Designer 一起使用)和 javascript(默认:javascript)
  • 您可以选择操作“len”属性是否仅计算 PHP 方法的所需参数,还是计算所有参数(默认:所有参数)
  • 您可以选择是否在 API 中声明继承的方法(默认:不声明)
  • 您可以选择是否在 API 中声明静态方法(默认:不声明)
  • 您可以选择是否从 API 中排除特定的公共方法(@extdirect-exclude)
  • 如果调用的是静态方法,是否实例化对象?您选择!(默认:不实例化)
  • 是否使用操作参数调用类构造函数?您选择!(默认:不调用)
  • “debug”选项用于在 API 操作结果输出中发送服务器异常(默认:关闭)
  • “utf8_encode”选项用于在 API 操作结果中自动应用 UTF8 编码(默认:关闭)
  • 您可以选择是否将参数转换为关联数组(默认:不转换)
  • 处理表单
  • 处理文件上传 配置 - 如何操作

简单。如果配置选项名称是“configuration_name”,并且配置值是 $value,使用此语法

ExtDirect::$configuration_name = $value;  

就是这样。

配置选项

  • name: api_classes
    type: 字符串数组或键值对
    meaning: 发布到 Ext.Direct API 的类名。可以是字符串或键值对:键是 API 名称,值是类。
    default: empty
    comments: 如果您为 ExtDirect::provide 方法提供了非空的 api_classes 参数,则此选项将被覆盖。选择一个或另一个。如果您想声明单个类,可以将 api_classes 设置为字符串,而不是数组
    example
  ExtDirect::$api_classes = ['MyClass', 'AnotherClass'=>'MyNamespace\\AnotherClass'];
  • name: api_classes_discovery_dirs
    type: 数组 meaning: 这些目录将被递归扫描,并添加具有 @extdirect-api 属性的类到 api_classes 选项。
    键是路径,值是命名空间。
    default: empty
    comments: 警告:如果发现目录中有许多文件,此选项可能会减慢响应时间。您可以从 ExtDirect::discover_api_classes() 获取发现类并将它们保存到缓存中
    example
  ExtDirect::$api_classes_discovery_dirs = [__DIR__ . '/MyNamespace/MyAPI' => 'MyNamespace\\MyAPI'];
  • name: url
    type: 字符串
    meaning: Ext.Direct API 属性 "url"
    default: $_SERVER['PHP_SELF']
    comments: 有时,PHP_SELF 可能不是我们想要的。因此,可以手动指定 API URL
    example
  ExtDirect::$url = '/path/to/my_php_script.php';  
  • name: namespace
    type: 字符串
    意义:Ext.Direct API 属性 "namespace"
    默认值:Ext.php
    注释:请根据 ExtJS 的命名空间规则自由选择您的命名空间。
    example
  ExtDirect::$namespace = 'Ext.php'; 
  • 名称:descriptor
    type: 字符串
    意义:Ext.Direct API 属性 "descriptor"
    默认值:Ext.php.REMOTING_API
    注释:请根据 ExtJS 的规则和所选命名空间自由选择您的描述符。
    example
  ExtDirect::$descriptor = 'Ext.php.REMOTING_API';  
  • 名称:id
    type: 字符串
    意义:Ext.Direct 提供者属性 "id"
    default: empty
    example
  ExtDirect::$id = 'MyProvider';  
  • 名称:max_retries
    类型:int
    意义:调用失败时重新尝试发送的次数
    默认值:1
    example
  ExtDirect::$max_retries = 1;  
  • 名称:timeout
    类型:int
    意义:在此远程 API 中,每个方法调用使用的超时时间(毫秒)
    默认值:30000
    example
  ExtDirect::$timeout = 30000;  
  • 名称:count_only_required_params
    类型:boolean
    意义:将此设置为 true 以仅计算方法的 API "len" 属性的必需参数
    默认值:false
    example
  ExtDirect::$count_only_required_params = true;  
  • 名称:include_static_methods
    类型:boolean
    意义:将此设置为 true 以在 API 声明中包含静态方法
    默认值:false
    example
  ExtDirect::$include_static_methods = true;  
  • 名称:include_inherited_methods
    类型:boolean
    意义:将此设置为 true 以在 API 声明中包含继承的方法
    默认值:false
    example
  ExtDirect::$include_inherited_methods = true;
  • 名称:instantiate_static
    类型:boolean
    意义:将此设置为 true 以创建一个类对象实例,即使被调用的方法是静态的
    默认值:false
    example
  ExtDirect::$instantiate_static = true;
  • 名称:constructor_send_params
    类型:boolean
    意义:将此设置为 true 以调用动作类构造函数并向其发送动作参数
    默认值:false
    example
  ExtDirect::$constructor_send_params = true;
  • 名称:constructor_params
    类型:array
    意义:要发送到类构造函数的参数(使用类键作为名称)
    默认值:[]
    example
  ExtDirect::$constructor_params = ['MyNamespace\\MyClass' => ['param1', 'param2']];
  • 名称:debug
    类型:boolean
    意义:将此设置为 true 以允许输出异常详细信息
    默认值:false
    example
  ExtDirect::$debug = true;
  • 名称:utf8_encode
    类型:boolean
    意义:将此设置为 true 以通过 utf8_encode 函数传递所有动作方法调用的结果
    默认值:false
    example
  ExtDirect::$utf8_encode = true;  
  • 名称:params_enforce_associative
    类型:boolean
    意义:将此设置为 true 以通过 json_decode(json_encode($params), true) 传递所有动作参数
    默认值:false
    example
  ExtDirect::$params_enforce_associative = true;  
  • 名称:default_api_output
    类型:string 意义:API 输出格式 - 可用选项为 "json"(适用于 Ext Designer)和 "javascript"
    默认值:javascript
    注释:另一种强制 "json" 输出的方法是,在您的 PHP 脚本 URL 的末尾附加 "?json" 查询字符串;在引用您的 API 的 HTML <script> 标签中这样做
    example
  ExtDirect::$default_api_output = 'javascript';  

表单处理器

有两种不同的方法可以将方法标记为 formHandler

方法 1:使用新的 ExtDirect::$form_handlers 配置选项。

  • 名称:form_handlers 类型:字符串数组
    意义:要标记为 Ext.Direct API 中的 formHandler 的类/方法名称
    默认值:[]
    注释:每个方法的字符串格式必须是 "className::methodName"
    example
  ExtDirect::$form_handlers = ['someClass::someMethod', 'MyNamespace\\Server::date'];  

方法 2:在方法的 DOC 注释中包含 @extdirect-formHandler

示例

class FTP_Manager
{
    /**
    * Sets FTP password for a specific account
    * 
    * @extdirect-formHandler
    * @param string $account   Name of the account
    * @param string $password   New password
    * @param string $password_confirm   New password confirmation
    * @return string
    */
    public function set_ftp_password($account, $password, $password_confirm)
    {
        // do stuff
        return 'result';
    }
}  

在上面的示例中,由于方法 DOC 注释中的 @extdirect-formHandler 字符串,它将被标记为 formHandler 方法。

它具有与以下相同的效果

ExtDirect::$form_handlers[] = 'FTP_Manager::set_ftp_password';  

接收参数

表单发送的参数被调整为可以由类方法接收。

请注意,这不是常规操作。

我将使用上面的 "set_ftp_password" 方法作为示例。

首先,请注意我们不想所有 formHandler 方法都有相同的不友好签名,如下所示

function set_ftp_password($data){};
function do_something($data){};
function do_something_completely_different($data){};  

$data 是用户输入(通常是 $_POST

因此,为了能够保持正常的方法签名,如下所示...

function set_ftp_password($account, $password, $password_confirm){}

...我已经实现了以下解决方案

当方法/操作函数是 formHandler 时,其参数值是从与参数名称匹配的输入名称中获取的。

所以... $_POST['account'] 将自动成为 $account 参数...

$_POST['password'] 的值将是 $password 参数的值...

...那么 $password_confirm 参数的值从哪里来?是的!从 $_POST['password_confirm']

就是这样:方法参数的名称与 $_POST 数组的键匹配。

优点

  • 不需要担心参数顺序
  • 可以使用有意义且清晰的函数签名
  • 不需要检查 $_POST 数组 - ExtDirect 控制器会为我们做这件事(忘记 "isset" 检查...如果某个参数值未在 $_POST 数组中设置,则传递默认值(如果有)或 null 给方法/函数)

缺点

  • 输入名称必须与方法/函数参数名称匹配(在我看来,这是一个优点!)
  • 这种方法可能并不适合你(在这种情况下,只需忽略所有这些内容,直接使用 $_POST / $_GET / $_REQUEST 数组!)

当然,所有输入数据的验证/过滤/净化都必须仔细考虑。

关于文件上传的附加说明

如果你的文件输入名称是 userFile,它将作为名为 $userFile 的参数可用

换句话说:你的 $userFile 参数将接收到来自 $_FILES['userFile'] 的值

拦截函数

  • declare_method_function
  • authorization_function
  • instantiate_function
  • transform_result_function
  • transform_response_function

使用 declare_method_function,你可以确定是否允许方法声明。

现在,你能够指定一个 authorization_function,在那里你可以检查用户权限并相应地返回 true 或 false,允许或不允许 API 调用。

instantiate_function 将在 API 动作调用中调用,以实例化类的对象。如果你使用 DI 容器实例化类,这将很有用。

使用 transform_result_function,你可以在 API 方法调用执行后修改其结果,但在发送到客户端之前。

最后,使用 transform_response_function,你可以修改响应结构。这允许触发服务器端事件,并将额外的服务器端数据与 RPC 结果一起发送。

// New configuration option
ExtDirect::$id = 'my_api';

// All "function" configurations accept parameters of callback type
ExtDirect::$declare_method_function     = 'declare_method';
ExtDirect::$authorization_function      = 'authorize';
ExtDirect::$instantiate_function        = 'instantiate';
ExtDirect::$transform_result_function   = 'transform_result';
ExtDirect::$transform_response_function = 'transform_response';

function declare_method(string $class, string $method) : bool
{
    // return boolean - declare the method in the API or not
    return in_array($class . '::' . $method, MyFramework::$user->permissions);
}

function authorize(ExtDirectAction $action, callable $callback, array $parameters) : bool
{
    // return boolean - authorize the action call or not
    return declare_method($action->class, $action->method);
}

function instantiate(ExtDirectAction $action) : object
{
    // return instance of class
    return DI::get($action->class);
}

function transform_result(ExtDirectAction $action, mixed $result) : mixed
{
    if ($action->form_handler)
        $result = ['success' => $result];

    // return modified result
    return $result;
}

function transform_response(ExtDirectAction $action, array $response) : array
{
    $response['error_msg']   = MyFramework::$errors;
    $response['success_msg'] = MyFramework::$success;

    // return modified response
    return $response;
}