The starter introduces really simple but very helpful service container for better organization and separation of your code. Let's quote some definition:
A Service Container is a special object that manages the instantiation of services inside an application. Instead of creating services directly, the developer trains the service container (via configuration) on how to create the services. -- Symfony Glossary
It sounds scary, but it is an easy concept. Let's see some examples.
Usage
All of your bindings should be defined inside app/Setup/services.php
file.
It's recommended to use a theme()
helper function for operating on service container; this gives you an ability to access the container anywhere in your project components.
Please, visit the Theme Service Container documentation for a more detailed description about API.
Creating services
You should register your project bindings within a named function which is attached to the init
action hook. This will give you a confidence that everything is booted and ready for binding.
Register your service with theme()
helper inside the hooked function. Remember to import a proper use statement (use function Tonik\Theme\App\theme
).
namespace Tonik\Theme\App\Setup;
use function Tonik\Theme\App\theme;
function bind_service()
{
theme()->bind('service', function() {
return true;
});
}
add_action('init', 'Tonik\Theme\App\Setup\bind_service');
Retrieving services
After service registration, you can also retrieve it with theme()
helper function. Pass its name as the first parameter or use get
method.
theme('service');
theme()->get('service');
To resolve services with additional parameters pass an associative array of key and values as the second argument.
theme('service', ['key' => 'value']);
Now, you have access to these parameters inside service closure in the second argument.
theme()->bind('service', function(Theme $theme, array $parameters) {
// $parameters: ['key' => 'value']
});
Examples
Services for database queries
Standard binding with bind
resolves service only once and returns a deposited value on every retrieving. It's a great place for fetching entries from the database because it gives you a certainty that you are querying your database only once.
namespace Tonik\Theme\App\Setup;
use WP_Query;
use Tonik\Gin\Foundation\Theme;
use function Tonik\Theme\App\theme;
/**
* Service handler for retrieving posts of specific post type.
*
* @return void
*/
function bind_books_service()
{
/**
* Binds service for retrieving posts of specific post type.
*
* @param \Tonik\Gin\Foundation\Theme $theme Instance of the service container
* @param array $parameters Parameters passed on service resolving
*
* @return \WP_Post[]
*/
theme()->bind('books', function (Theme $theme, $parameters) {
return new WP_Query([
'post_type' => 'book',
]);
});
}
add_action('init', 'Tonik\Theme\App\Setup\bind_books_service');
Now, you can simply retrieve posts of book post type anywhere in your project via registered service.
$genres = theme('books');
However, take note that bounded services always returns deposited value after first retrieving. If you want to pass dynamic parameters to service you probably need to register service as a factory:
theme()->factory('book/genres', function (Theme $theme, $parameters) {
return wp_get_post_terms($parameters['id'], 'book_genre');
});
$genres = theme('book/genres', ['id' => get_the_ID()]);
Services for external API requests
You may also define services which connect to the external resources. Use in pair with transients to achieve the best performance.
namespace Tonik\Theme\App\Setup;
use function Tonik\Theme\App\theme;
/**
* Service handler for retriving data from API.
*
* @return void
*/
function bind_api_endpoint_service()
{
/**
* Bind service for retrieving data from API.
*
* @return array
*/
theme()->bind('api/endpoint', function () {
if (false === ($response = get_transient('api/endpoint/transient'))) {
$response = wp_remote_post("https://api.io/endpoint", [
'body' => [
'client_id' => CLIENT_ID,
'secret_key' => SECRET_KEY
]
]);
set_transient('api/endpoint/transient', $response, DAY_IN_SECONDS);
}
return json_decode($response['body']);
});
}
add_action('init', 'Tonik\Theme\App\Setup\bind_api_endpoint_service');
You should define APIs configuration keys as constants in the wp-config.php
file.
define('CLIENT_ID', 'client-id');
define('SECRET_KEY', 'secret-key');
Now, with a simple resolving, you can pull external API data.
$auth = theme('api/endpoint');