mkuettel/codeigniter4-services

CodeIgniter 4 服务层库

v0.0.14 2024-05-09 13:42 UTC

README

pipeline status coverage report

这个库应该使为CodeIgniter4应用程序提供服务层变得更加容易。此外,还有一些工具可以与模型层交互,特别是这个库包含一个服务,用于提供更优雅和更可靠的数据库事务语法。

安装

您可以使用composer将此库添加到您的项目中。

composer require mkuettel/codeigniter4-services

就这么多,但您可能想更改一些配置,如下一节所述。

配置

src/Config目录中提供了多个配置文件。您可以将这些文件复制到您的项目中,并从类扩展以覆盖默认配置。

(未来将添加发布脚本以将这些文件复制到您的项目中)

服务接口

此库提供接口\MKU\Services\ServiceInterface

想法是通过定义另一个接口来扩展此接口,以实现您自己的服务。在此接口中,您定义服务将具有的所有方法

use \MKU\Services\ServiceInterface;

interface MyBusinessService extends ServiceInterface {
    public function placeOrder(Order $order): Result;
    public function sendOrderConfirmationMail(Order $order): Result;
    // ...
}

然后,通过您自己的服务类实现此接口。


class SimpleBusinessService extends MyBusinessService {
    
    private OrderModel $orderModel;
    private MailService $mailService;

    public function __construct(OrderModel $orderModel, MailService $mail) { /* ... */ }
    public function shortname(): string { return 'simple_business'; } 
    public function placeOrder(Order $order): Result { /* */ }
    public function sendOrderConfirmationMail(Order $order): Result { /* */ }
    // ...
}

您还需要实现shortname(): string方法,该方法返回此服务实现的唯一标识符。

shortname将后来用于使用以下方式获取或创建实现服务类的实例

 service('<shortname>'); 
 \Config\Services::shortname();

但为了使其工作,您必须现在按照以下方式注册它

class Services extends BaseService {
    
    // ....
    
    // use the same parameters as required by the constructor of the service class,
    // but make them null by default.
    public function business_simple() (
        OrderModel $orderModel = null,
        MailService $mail = null,
        bool $getShared = true // add extra parameter to reuse past instance if available (e.g. a singleton instance)
    ): SimpleBusinessService {
        if ($getShared) return self::getSharedInstance('simple_business', $config, $db);
        return new SimpleBusinessService(
            $orderModel ?? model(OrderModel::class);
            $mail ?? self::mail_service(),
        );
    }
    
    // use the interface as return type here
    public function business(): MyBusinessService {
        // change which service class to use for the MyBusinessService interface here
        return self::business_simple();
    }
    
    // ....
}

TODO(因此,这不应手动完成):将ServiceContainer作为\Config\Services的基础类添加,它根据其构造函数类型或注释自动配置服务,并在\Config\Services中创建构建方法。

事务服务

此库提供TransactionService,允许您在数据库事务期间执行自定义函数

// PHP 7.4+ using arrow functions
service('transaction')->transact(fn() => do_database_operation())

// Using anonymous function (or any Closure)
service('transaction')->transact(function() use ($db) {
    $db->insert( /* update */ ); ...
    $db->update( /* ...  */); ...
});

以这种方式使用,事务服务在执行给定的闭包之前开始事务。如果在事务期间发生异常,则事务将回滚。

嵌套事务

如果底层数据库驱动程序和数据库支持,则事务可以嵌套。目前,这些驱动程序并未对所有驱动程序完全实现,但此存储库提供了一个替代方案,它通过使用保存点扩展了CI4数据库驱动程序SQLite & MySQLi,以支持嵌套事务。

您可以通过设置.env文件或数据库配置中的DBDriver选项来使用它们

# .env
# ...
# use mysqli driver with support for nested transactions
database.default.DBDriver = '\MKU\Services\Database\Transactional\MySQLi'
# ...
# use SQLite3 driver with support for nested transactions
database.tests.DBDriver = '\MKU\Services\Database\Transactional\SQLite3'

此外,不同的驱动程序和数据库可能具有不同的事务保证和隔离级别。还要注意自动提交行为,这在某些数据库系统中可能是默认启用的。

DataProviderPersistenceService

此库还提供DataProvider接口和PersistenceService接口。这些接口旨在在服务层中用于与模型层交互。想法是通过仅返回实体对象而不是数据库连接句柄、查询结果对象或其他数据库特定对象,将数据访问层(模型、CodeIgniter数据库内容)与业务逻辑层(控制器)分开。

为了使持久化服务能够正确识别和处理实体,用作数据提供程序或持久化服务参数的实体类必须实现ServiceEntity接口,这迫使您定义主键(或者声明实体没有主键)。如果您有一个扩展自CodeIgniter实体(这不是必需的)类的实体类,您可以使用CodeIgniterServiceEntityTrait来使用定义的$primaryKey属性。

数据提供程序是查询并作为实体对象提供数据的服务,但本身不修改数据。DataProvider接口提供了以下三个基本方法:

interface DataProvider {
    public function get($id): ?ServiceEntity;
    public function refresh(ServiceEntity $id): ?bool;
    public function exists($id): bool;
}

$id是要查询的实体的主键,这也可以是多个属性的数组。您可以通过在实体类中实现ServiceEntity来定义此属性。

持久化服务是数据提供程序的扩展,也需要实现修改它们提供的数据的方法。以下提供了一些附加方法:

interface PersistenceService extends DataProvider {
    public function save(ServiceEntity $entity): Result;
    public function delete($id): ServiceEntity|bool;
}

可配置服务

目前只有一个名为MKU\Services\Library\Config\Configurable的接口和同一命名空间下的ConfigurableTrait,简化了前者的实现。

想法是您使用Trait并在服务中实现applyConfig()方法,使用您自己的自定义CodeIgniter配置类进行配置。

这个特性尚未完全构思,非常实验性,可能会发生变化。

贡献

如果您想为此项目做出贡献,请给我发消息。我很高兴收到反馈和建议。

欢迎在我的GitHub仓库提交拉取请求和错误报告

https://github.com/mkuettel/codeigniter4-services