Le gestionnaire de service (Container) embarqué dans Dotclear ne permettait pas de passer à ses services le container lui-même, c'est désormais possible depuis Dotclear 2.36. Une autre limite du container était qu'on ne pouvait pas récupèrer d'instance d'une service pour un usage isolé sans propager les intercations à tout le container. Pour faire simple si on modifiait les paramètres d'un service, cela modifiait ce service pour tout le script. Il est désomrais possible de créer des instances de service à usage ponctuel.
L'appel d'un service avec le paramètre NULL permet d'avoir une instance isolée de ce service. Les valeurs TRUE et FALSE de ce paramètre ont toujours les mêmes fonction qu'avant.
Voici un exemple complet montrant le passage du container au service et l'utilisation du paramétre NULL à la récupération du service :
<?php
use Dotclear\Helper\Container\Container;
use Dotclear\Helper\Conttainer\Factories;
// Class du service
class MonService
{
protected int $nb = 0;
// On passe le container directement au service
public function __construct(
protected MonContainer $container
) {
}
// On met en mémoire du service un nombre
public function nombre(int $nb): void
{
$this->nb = $nb;
}
// On lance un calcul en utilisant une methode du container
public function calcul(): string
{
$somme = $this->container->ajoute($this->nb);
return 'resultat : ' . $somme . "\n";
}
}
// Class du container
class MonContainer extends Container
{
public const CONTAINER_ID = 'moncontainer';
public function __construct()
{
parent::__construct(Factories::getFactory(static::CONTAINER_ID));
}
// Methode qui fait une addition
public function ajoute(int $nb): int
{
return $nb + $nb;
}
}
// On ajoute le service au container
Factories::addService('moncontainer', 'monservice', MonService::class);
// On crée l'instance du container
$container = new MonContainer();
// On récupère une instance du service depuis le container
$a = $container->get('monservice');
// On lui donne un nombre
$a->nombre(2);
// On fait une première fois le calcul
echo $a->calcul(); // resultat : 4
// On donne un autre nombre à notre instance du sevice
$a->nombre(3);
// On calcul, le résultat prend en compte le dernier nombre soumis
echo $a->calcul(); // resultat : 6
// On recupère une instance du service depuis le container
$b = $container->get('monservice');
// Même sans soumettre de nombre,
// on voit que le calcul se fait sur la même instance de service que précédement.
echo $b->calcul(); // resultat : 6
// On vérifie, et effectivement les deux instances a et b sont en réalité la même
echo $a->calcul(); // resultat : 6
// On récupère une nouvelle instance avec le parametre null
$c = $container->get('monservice', null);
// On donne à cette instance un nombre
$c->nombre(4);
// Le calcul prend bien en compte ce nombre
echo $c->calcul(); // resultat : 8
// On refait le calcul sur l'instance précédente, elle a bien gardé en mémoire le nombre précèdent
echo $b->calcul(); // resultat : 6
// Ce sont bien cette fois deux instances distinctes
// On récupère une instance du service depuis le container
$d = $container->get('monsevrice');
// On fait un calcul sans donner de nombre
echo $d->calcul(); // resultat: 6
// on voit que $c avec le paremetre null n'a pas d'influence sur les autres instances
Attention aux effets de bords, les objets partagés dans ces instances peuvent être modifiés dans une instance et renvoyer un résultat inattendu dans une autre instance !
A noter que tous les constructeurs des classes de premier niveau de Dotclear, celles qui sont disponibles dans le container principal, utilisables depuis App::xxx() ont désormais le container comme paramètre.
Par exemple classe Auth est passée de ça :
class Auth
{
// ...
/**
* Constructs a new instance.
*
*@param BlogInterface $blog The blog instance
* @param BlogsInterface $blogs The blogs handler
* @param ConfigInterface $config The configuration instance
* @param DatabaseInterface $db The database handler instance
* @param SessionInterface $session The session handler
* @param UserPreferencesInterface $user_prefs The user preferences instance
* @param UsersInterface $users The users handler
*/
public function __construct(
protected BlogInterface $blog,
protected BlogsInterface $blogs,
protected ConfigInterface $config,
protected DatabaseInterface $db,
protected SessionInterface $session,
public UserpreferencesInterface $user_prefs,
protected UsersInterface $users
) {
// ...
}
// ...
}
à ça :
class Auth
{
// ...
/**
* Constructs a new instance.
*
* @param Core $core The core container
*/
public function __construct(
protected Core $core
) {
// ...
}
// ...
}
Certains y veront le grand retour de $core, mais il n'en est rien, car cela n'est effectif que dans les classes de premier niveau, associées au container.
Appel aux classes de context
Les instances de classes appartenant aux contextes (Utility) telles que Frontend, Backend, Upgrade et Install sont désormais disponibles comme méthodes du contexte. Il n'est plus nécessaire de déclarer l'utilisation des classes comme \Dotclear\Core\Backend\Favorites::class pour les utiliser, car elles sont maintenant directement disponibles dans l'objet du contexte, ce qui donnera pour l'exemple App::backend()->favorites();
Voici une liste des classes de second niveau pour le Backend :
- Dotclear\Core\Backend\Action::class => App::backend()->action(), (nouvelle classe, voir plus bas)
- Dotclear\Core\Backend\Auth::class => App::backend()->auth(), (nouvelle classe, voir plus bas)
- Dotclear\Core\Backend\Combos::class => App::backend()->combos(),
- Dotclear\Core\Backend\Favorites::class => App::backend()->favorites(),
- Dotclear\Core\Backend\Filter::class => App::backend()->filter(), (nouvelle classe, voir plus bas)
- Dotclear\Core\Backend\Helper::class => App::backend()->helper(),
- Dotclear\Core\Backend\Listing::class => App::backend()->listing(), (nouvelle classe, voir plus bas)
- Dotclear\Core\Backend\MediaPage::class => App::backend()->mediaPage(),
- Dotclear\Core\Backend\Menus::class => App::backend()->menus(),
- Dotclear\Core\Backend\ModulesList::class => App::backend()->modulesList(),
- Dotclear\Core\Backend\Notices::class => App::backend()->notices-),
- Dotclear\Core\Backend\Page::class => App::backend()->page(),
- Dotclear\Core\Backend\Resources::class => App::backend()->resources(),
- Dotclear\Core\Backend\ThemeConfig::class => App::backend()->themeConfig(),
- Dotclear\Core\Backend\ThemesList::class => App::backend()->themesList(),
- Dotclear\Core\Backend\Url::class => App::backend()->url(),
- Dotclear\Core\Backend\UserPref::class => App::backend()->userPref(),
Les nouvelles classes de Backend utiles aux listes que sont Action, Filter et Listing fournissent les instances des objets suivant :
- Dotclear\Core\Backend\Action\ActionsBlogs => App::backend()->action()->blogs(...)
- Dotclear\Core\Backend\Action\ActionsComments => App::backend()->action()->comments(...)
- Dotclear\Core\Backend\Action\ActionsPosts => App::backend()->action()->posts(...)
- Dotclear\Core\Backend\Filter\FilterBlogs => App::backend()->filter()->blogs(...)
- Dotclear\Core\Backend\Filter\FilterComments => App::backend()->filter()->comments(...)
- Dotclear\Core\Backend\Filter\FilterMedia => App::backend()->filter()->media(...)
- Dotclear\Core\Backend\Filter\FilterPosts => App::backend()->filter()->posts(...)
- Dotclear\Core\Backend\Filter\FilterUsers => App::backend()->filter()->users(...)
- Dotclear\Core\Backend\Listing\ListingBlogs => App::backend()->listing()->blogs(...)
- Dotclear\Core\Backend\Listing\ListingCommnets => App::backend()->listing()->comments(...)
- Dotclear\Core\Backend\Listing\ListingMedia => App::backend()->listing()->media(...)
- Dotclear\Core\Backend\Listing\ListingPosts => App::backend()->listing()->posts(...)
- Dotclear\Core\Backend\Listing\ListingPostsMini => App::backend()->listing()->postsMini(...)
- Dotclear\Core\Backend\Listing\ListingUsers => App::backend()->listing()->users(...)
- Dotclear\Core\Backend\Listing\Pager => App::backend()->listing()->pager(...)
Une autre nouvelle classe fournit les instances des objets nécessaires aux connections tierces :
- Dotclear\Core\Backend\Auth\Otp => App::backend()->auth()->otp(...)
- Dotclear\Core\Backend\Auth\WebAuthn => App::backend()->auth()->webauthn(...)
- Dotclear\Core\Backend\Auth\OAuth2Client => App::backend()->auth()->oauth2(...)
Voici une liste des classes de second niveau pour le Frontend :
- Doclear\Core\Frontend\Ctx::class => App::frontend()->context(),
- Doclear\Core\Frontend\Tpl::class => App::frontend()->template(),
- Doclear\Core\Frontend\XmlRpc::class => App::frontend()->xmlrpc(),
Les plugins et thèmes, en pouvant accèder directement depuis le contexte à ces objets, ne devraient plus avoir à déclarer des classes appartenant aux Backend ou Frontend hormis lors de la création de liste pour étendre une classe.
.