3 * @copyright Copyright (C) 2010-2023, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Core\Hooks\Model;
25 use Friendica\Core\Hooks\Capabilities\IAmAStrategy;
26 use Friendica\Core\Hooks\Capabilities\ICanManageInstances;
27 use Friendica\Core\Hooks\Exceptions\HookInstanceException;
28 use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException;
31 class InstanceManager implements ICanManageInstances
33 protected $instance = [];
34 protected $instanceArguments = [];
35 protected $decorator = [];
40 public function __construct(Dice $dice)
46 public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): ICanManageInstances
48 if (!is_a($class, $interface, true)) {
49 throw new HookRegisterArgumentException(sprintf('%s is not a valid class for the interface %s', $class, $interface));
52 if (!is_a($class, IAmAStrategy::class, true)) {
53 throw new HookRegisterArgumentException(sprintf('%s does not inherit from the marker interface %s', $class, IAmAStrategy::class));
56 if (!empty($this->instance[$interface][$name])) {
57 throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface));
60 $this->instance[$interface][$name] = $class;
61 $this->instanceArguments[$interface][$name] = $arguments;
67 public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): ICanManageInstances
69 if (!is_a($decoratorClass, $class, true)) {
70 throw new HookRegisterArgumentException(sprintf('%s is not a valid substitution for the given class or interface %s', $decoratorClass, $class));
73 $this->decorator[$class][] = [
74 'class' => $decoratorClass,
75 'arguments' => $arguments,
82 public function getInstance(string $class, string $name, array $arguments = []): object
84 if (empty($this->instance[$class][$name])) {
85 throw new HookInstanceException(sprintf('The class with the name %s isn\'t registered for the class or interface %s', $name, $class));
88 $instance = $this->dice->create($this->instance[$class][$name], array_merge($this->instanceArguments[$class][$name] ?? [], $arguments));
90 foreach ($this->decorator[$class] ?? [] as $decorator) {
91 $this->dice = $this->dice->addRule($class, [
92 'instanceOf' => $decorator['class'],
93 'constructParams' => empty($decorator['arguments']) ? null : $decorator['arguments'],
94 /// @todo maybe support call structures for hooks as well in a later stage - could make factory calls easier
96 'substitutions' => [$class => $instance],
99 $instance = $this->dice->create($class);