jeyroik/extas-foundation

此包的最新版本(6.22.1)没有可用的许可证信息。

Extas 基础包


README

PHP Composer codecov.io Latest Stable Version Total Downloads Dependents

描述

该包包含 Extas 的基本实体

  • extas\components\Item 基础对象,允许使用开箱即用的插件和扩展(见下文)
  • extas\components\plugins\Plugin 插件。允许实现插件(详细信息见下文)。
  • extas\components\extensions\Extension 扩展。允许为从 Item 继承的类实现扩展(装饰器)。

要求

  • PHP 7.4+
  • 任何存储(默认使用 JSON 文件进行测试)。

安装包

# composer require jeyroik/extas-foundation:6.*

安装 Extas 兼容的应用程序

# vendor/bin/extas install -t "repo/template/path" -s "repo/classes/save/path"

对于实体,有一个 extas\\interfaces\\stages\\IStageBeforeInstallEntity 阶段,通过连接到该阶段可以对实体数据进行额外操作。

应用程序的实体配置先于库的实体配置。

# vendor/bin/extas-extra e

有关 extra 命令的详细信息,请参阅下文。

安装其他实体

要安装其他实体,可以使用 extra 命令。通过插件,可以连接到该命令,并通过统一接口安装任何实体,并执行所需的各种操作。

要查看可用选项的列表,请使用命令的帮助

# vendor/bin/extas extra -h

应用程序配置

  • 为了配置您的应用程序,需要创建两个文件
    • extas.app.storage.json 用于配置存储、插件和扩展;
    • extas.app.json 用于配置实体。
    • 最小配置可以在 extas.app.storage.dist.json 中找到,以及在下文的当前文档中。
      • extas.app.dist.json,以及在下文的当前文档中。
      • 如果开发库,则必须将库的配置存储在
  • extas.storage.json - 存储配置、插件和扩展。
    • extas.json - 实体配置。
    • extas.storage.dist.json,以及在下文的当前文档中。
    • 最小配置可以在 extas.app.storage.dist.json 中找到,以及在下文的当前文档中。
      • extas.dist.json,以及在下文的当前文档中。
      • extas.dist.json,以及在下文的当前文档中。

运行测试

# composer test

使用

Item

应该将基本实体用作您的实体(模型等)的父类。

class My extends extas\components\Item

在这种情况下,您将立即获得

  • 动态属性支持:$my = new My(); $my->some = 'thing';
  • 数组接口支持
$my = new My();
$my['fieldName'] = 5;
$val = $my['fieldName'];
echo $val;// 5
isset($my['fieldName']); // true
unset($my['fieldName']);
isset($my['fieldName']); // false
  • 迭代器支持:foreach($my as $field => $value)
  • 装饰器支持:$my->notExistingMethod($arg1, $arg2)
  • 快速访问存储支持:$my->myTable()->one(...)
  • 插件(事件)支持:在 My 类的方法内部
    • 创建实体 <实体>.created,在将新实体实例保存到存储时触发;
    • 实体初始化 <实体>.init,在初始化实体对象时触发;
    • 实体对象删除 <实体>.after,在删除实体对象时触发
    • 分别转换为数组、字符串和整数 <实体>.to.array<实体>.to.string<实体>.to.int
  • 支持一系列辅助方法(每个方法都为插件提供相应的事件)类型
    • __toArray()
    • __toJson()
    • __toInt()
    • __equal(IItem $other) - 与其他实体比较。
    • __has('attr1', 'attr2', ...) - 检查是否存在必要的属性。
    • __select('attr1', 'attr2', ...) - 获取具有有限字段集的实体。
  • 支持为插件创建新事件
foreach($this->getPluginsByStage('event.name') as $plugin)
{
    $plugin($arg1, $arg2);
}

以下,在审查每个基本实体之后,将展示一个使用所有实体(整体和单独)的工作示例。

插件

应将插件用作您插件的父类。

class MyPlugin extends extas\components\plugins\Plugin {}

要实现插件,您需要重载 __invoke() 方法。方法参数取决于具体阶段(事件)。

下面是插件实现的示例。

预安装插件

在应用程序的 extas.app.storage.json 和库的 extas.storage.json 中。

{
  "plugins": [
    {
      "class": "class\\Name",
      "stage": "stage.name",
      "priority": 10
    }
  ]
}

priority - 优先级越高,插件越早(相对于同一阶段的其他插件)执行。此参数是可选的。

扩展

应将扩展用作您扩展(装饰器)的父类。扩展允许动态且透明地向实体添加方法,而不修改其代码。

class MyExtension extends extas\components\Extension implements IMyExtension{}

预安装扩展

在应用程序的 extas.app.storage.json 和库的 extas.storage.json 中。

{
  "extensions": [
    {
      "class": "extension\\Class",
      "interface": "extension\\Interface",
      "subject": ["subject.name.1", "subject.name.2", "*"],
      "methods": ["method1", "method2"]
    }
  ]
}

单独和一起使用每个实体的示例

Item

namespace my\extas;

use extas\components\Item;

class My extends Item
{
    public function getName()
    {
        return $this->config['name'] ?? '';
    }
    
    public function setName($name)
    {
        $this->name = $name;
        
        return $this;
    }

    protected function getSubjectForExtension(): string
    {
        return 'my';
    }
}

$my = new my\extas\My(['name' => 'on init']);
echo $my['name']; // 'on init'
echo $my->getName(); // 'on init'
echo $my->name; // 'on init'
$my['description'] = 'Using Item example';

foreach($my as $field => $value) {
    echo $field . ' = ' . $value;
}

/** 
 * Will output:
 * name = on init
 * description = Using Item example
 */

插件

namespace my\extas;

use extas\components\Item;

class My extends Item
{
    public function getName()
    {
        $name = $this->config['name'] ?? '';
    
        foreach($this->getPluginsByStage('my.name.get') as $plugin) {
            $plugin($name);
        }
    
        return $name;
    }
    
    public function setName($name)
    {
        $this->config['name'] = $name;
        
        return $this;
    }

    protected function getSubjectForExtension(): string
    {
        return 'my';
    }
}

use extas\components\Plugin;

class PluginEmptyName extends Plugin
{
    public function __invoke(&$name)
    {
        $name = $name ?: 'Missed "name"';
    }
} 

// extas.storage.json/extas.app.storage.json
{
    "plugins": [
        {
            "class": "my\\extas\\PluginEmptyName",
            "stage": "my.name.get"
        }
    ]
}

// somewhere in a code

$my = new My();
echo $my->getName(); // 'Missed "name"'

注意!为了使上述示例生效,插件必须安装到系统中。详细信息请参阅 安装 部分。

扩展

namespace my\extas;

use extas\components\Item;

class My extends Item
{
    public function getName()
    {
        $name = $this->config['name'] ?? '';
    
        foreach($this->getPluginsByStage('my.name.get') as $plugin) {
            $plugin($name);
        }
    
        return $name;
    }
    
    public function setName($name)
    {
        $this->config['name'] = $name;
        
        return $this;
    }

    protected function getSubjectForExtension(): string
    {
        return 'my';
    }
}

/**
 * Для расширений рекомендуется всегда подготавливать интерфейсы.
 * Это помогает при разработке (подсказки) и позволяет удобнее контролировать расширения.
 */
interface IGetMutatedName
{
    /**
     * @return string
     */
    public function getMutatedName(): string;
}

use extas\components\Extension;

class MyGetMutatedName extends Extension implements IGetMutatedName
{
    public string $subject = 'my';

    /**
     * Последним аргументом любого метода, который является расширением,
     * передаётся экземпляр сущности, которая расширяется
     *
     * @param null|My $my
     * 
     * @return string
     */
    public function getMutatedName(My $my = null)
    {
        $name = $my->getName();
        return str_replace('.', '\\', $name);
    }
}

// extas.storage.json/extas.app.storage.json
{
    "extensions": [
        {
            "class": "my\\extas\\MyGetMutatedName",
            "interface": "my\\extas\\IGetMutatedName",
            "subject": ["my"],
            "methods": ["getMutatedName"]
        }
    ]
}

// somewhere in a code

$my = new My(['name' => 'extas.extensions.extension.example']);
echo $my->getMutatedName(); // extas\\extensions\\extension\\example

注意!为了使上述示例生效,扩展必须安装到系统中。详细信息请参阅 安装 部分。

extas.app.storage.json

{
    "name": "vendor/package",
    "drivers": [
        {
            "driver": "\\driver\\Class",
            "options": {
                "dsn": "{username}:{userpassword}@{host}:{port}/{db} | {path/to/db}",
                "username": "",
                "password": "",
                "host": "",
                "port": "",
                "db": ""
            },
            "tables": ["t1", ...]
        }
    ],
    "tables": {
        "some_entities": {
            "item_class": "",
            "pk": "",
            "aliases": ["alias1", ...],
            "hooks": {
                "create-before": true,
                "update-before": true,
                "update-after": true,
                ...
            },
            "code": {
                "create-before": "echo 'any code you want'; \\extas\\components\\repositories\\RepoItem::throwIfExist($this, $item, ['name'])",
                ...
            }
        }, 
        ...
    },
    "plugins": [
        {
            ...
        },
        ...
    ],
    "extensions": [
        {
            ...
        },
        ...
    ],
    "envs": [
        "name1": "description"
    ]
}

extas.app.json

应用程序的实体配置先于库的实体配置。

{
    "some_entities": [
        {
            ...
        },
        ...
    ]
}

extas.storage.json

注意:不要在此配置中将设置驱动器的部分放在这里 - 它将被忽略。驱动器在 extas.app.storage.json 中配置。

{
    "name": "vendor/package",
    "tables": {
        "some_entities": {
            "item_class": "",
            "pk": "",
            "aliases": ["alias1", ...],
            "hooks": {
                "create-before": true,
                "update-before": true,
                "update-after": true,
                ...
            },
            "code": {
                "create-before": "echo 'any code you want';",
                ...
            }
        }, 
        ...
    },
    "plugins": [
        {
            ...
        },
        ...
    ],
    "extensions": [
        {
            ...
        },
        ...
    ],
    "envs": {
        "name1": "description 1"
    }
}

extas.json

{
    "some_entities": [
        {
            ...
        },
        ...
    ]
}

ENV

要了解需要哪些环境变量,请执行 env 命令。

# vendor/bin/extas env

要将自己的环境变量添加到该列表中,请将 extas.app.storage.json(对于库在 extas.storage.json)配置中的 envs 部分添加,并按上述配置示例描述您的变量。