Abhängigkeiten in Legacy-Systemen verwaltbar machen

Seite 2: Struktur schaffen

Inhaltsverzeichnis

Im ersten Schritt sollte der Container zentral verfügbar gemacht werden. Die meisten Frameworks haben eine Registry für Services, die sich dazu nutzen lässt, den Container einzuhängen. Im Beispielprojekt wurde der Symfony Container Builder als Yii-Komponente realisiert:

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class YiiContainerComponent extends ContainerBuilder implements ↵
IApplicationComponent
{
/**
* @var bool
*/
private $isInitialized = false;

/**
* @var array
*/
private $configuration = [];

public function setConfiguration(array $configuration) {
$this->configuration = $configuration;
}

public function init()
{
foreach ($this->configuration as $aServiceId => ↵
$aServiceConfiguration) {
$this->register($aServiceId, ↵
$aServiceConfiguration['class']);

foreach ($aServiceConfiguration['arguments'] as ↵
$anArgument) {
if (strpos($anArgument, '@') === 0) {
$anArgument = new Reference(substr($anArgument,↵
1));
}
$definition->addArgument($anArgument);
}
}

$this->isInitialized = true;
}

/**
* @return bool
*/
public function getIsInitialized()
{
return $this->isInitialized;
}
}

Das Programm initialisiert und registriert Letztere in der Bootstrap-Datei. Da Services zudem Abhängigkeiten zu anderen Framework-Komponenten haben können, gibt es die Möglichkeit, synthetische Dienste zu definieren. Statt dass ein Container sie instanziiert, reichen andere Komponenten die Services von außen herein:

// ...

$app = Yii::createWebApplication($config);
$container = new YiiContainerComponent();
$container->setConfiguration([
'userRepository' => [
'class' => 'Module\User\Service\UserRepository',
'arguments' => ['@db'],
],
'userService' => [
'class' => 'Module\User\Service\UserService',
'arguments' => ['/data/users'],
],
]);

// set synthetic services
$container->set('db', Yii::app()->db);
$app->setComponent('container', $container);
$app->run();

Im Controller lassen sie sich dann aus dem Container holen, der sie bei Bedarf per Lazy Loading instanziiert:

class UserController extends FrameworkController
{
public function actionView($id)
{
$user = $this->getUserRepository()->find($id);

$photoPath = $this->getUserService()->getPhotoForUser($user);

$this->render('view', ['user' => $user, 'photoPath' => ↵
$photoPath]);
}

/**
* @return \Module\User\Service\UserRepository
*/
private function getUserRepository()
{
return $this->getContainer()->get('userRepository');
}

/**
* @return \Module\User\Service\UserService
*/
private function getUserService()
{
return $this->getContainer()->get('userService');
}

/**
* Diese Convenience-Methode sollte in einem Basis-Controller oder ↵
als Trait zur Verfügung gestellt werden.
*
* @return \Symfony\Component\DependencyInjection ↵
\ContainerInterface
*/
protected function getContainer()
{
return Yii::app()->getComponent('container');
}
}