This library should make it easier to facilitate a Service layer for CodeIgniter4 application. Additionally there are some tools to interact with the model layer, in particular this library contains a Service to have some nicer and more reliable syntax for database transactions.
You can add this library to your project using composer:
composer require mkuettel/codeigniter4-services
That's it, but you might want to change some of the configuration, as described in the next section.
There are multiple configuration files available in the src/Config directories. You can override these default configuration by copying the configuration file into your project and adjusting the values in your editor.
TODO: add publishable configuration
This Library provides the interface \MKU\Services\Service
.
The idea is that you extend from this interface by defining another interface for your own service. In this interface you define all the methods your service will have:
use \MKU\Services\Service;
interface MyBusinessService extends Service {
public function placeOrder(Order $order): Result;
public function sendOrderConfirmationMail(Order $order): Result;
// ...
}
You then implement this interface with your own service class.
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 { /* */ }
// ...
}
You'll also need to implement shortname(): string
method returning a unique identifier for
this service implementation.
The shortname will later be used to get or create an instance the implementing service class using:
service('<shortname>');
\Config\Services::shortname();
But for this to work you must for now register it as follows
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(so this must not be done manually): add ServiceContainer as a base class for \Config\Services which autoconfigures the services depending on their constructor types or annotations and creates the builder methods in \Config\Services.
This library provides a TransactionService, which allows you to execute a custom function during a database transaction:
// 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( /* ... */); ...
});
Used in this manner, the transaction service begins a transaction before executing the given closure. If an exception occurs during the transaction, the transaction will be rolled back.
Transactions can be nested.
NOTE: Not all database systems and engines support transactions by default, especially transactions with strict isolation between connections.
Future configuration options:
strictMode
: Whether to use strict transactions, meaning other connections cannot see your modifications until you commit?testMode
: Whether to rollback the transaction on exception? tbd.connection_type
: tbd