Skip to content

Instantly share code, notes, and snippets.

@janmarek
Created October 13, 2010 09:08
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janmarek/623720 to your computer and use it in GitHub Desktop.
Save janmarek/623720 to your computer and use it in GitHub Desktop.
Dependency Injection Container konfigurovatelný neonem pro Nette
Službě lze nastavit:
- factory - jméno továrničky
- class - jméno třídy
- arguments - pole parametrů konstruktoru nebo továrničky
- callMethods - pole volaných metod, kterým se také definují argumenty
Argumenty:
- začíná na $$ - Environment::getConfig
- začíná na $ - Environment::getVariable
- začíná na % - Context::getService
<?php
// ...
$serviceLoader = new ServiceLoader;
$serviceLoader->loadNeonConfigFiles(Nette\Environment::getContext(), array(
APP_DIR . "/services.neon",
));
// ...
<?php
namespace Neuron;
use Nette\Environment, Nette\String;
use Nette\NeonParser;
use Nette\Reflection\ClassReflection;
use Nette\IContext;
/**
* Service loader
*
* @author Jan Marek
*/
class ServiceLoader
{
public function loadNeonConfigFiles(IContext $context, array $configFiles)
{
$parser = new NeonParser;
foreach ($configFiles as $file) {
$config = $parser->parse(file_get_contents($file));
$this->loadConfig($context, $config);
}
}
public function loadConfig(IContext $context, $config)
{
foreach ($config as $serviceName => $serviceConfig) {
if ($context->hasService($serviceName)) {
$context->removeService($serviceName);
}
$options = null;
$singleton = isset($serviceConfig["singleton"]) ? (bool) $serviceConfig["singleton"] : true;
if (isset($serviceConfig["arguments"]) || isset($serviceConfig["callMethods"])) {
$service = array($this, "universalFactory");
if (isset($serviceConfig["class"])) {
$options["class"] = $serviceConfig["class"];
}
if (isset($serviceConfig["factory"])) {
$options["factory"] = $serviceConfig["factory"];
}
if (isset($serviceConfig["arguments"])) {
$options["arguments"] = $serviceConfig["arguments"];
}
if (isset($serviceConfig["callMethods"])) {
$options["callMethods"] = $serviceConfig["callMethods"];
}
$options["context"] = $context;
} elseif (isset($serviceConfig["factory"])) {
$service = $serviceConfig["factory"];
} elseif (isset($serviceConfig["class"])) {
$service = $serviceConfig["class"];
}
$context->addService($serviceName, $service, $singleton, $options);
}
}
public function processArguments($args, IContext $context)
{
return array_map(function ($arg) use ($context) {
if (!is_string($arg)) {
return $arg;
} elseif (String::startsWith($arg, "%")) {
return $context->getService(substr($arg, 1));
} elseif (String::startsWith($arg, "$$")) {
return Environment::getConfig(substr($arg, 2));
} elseif (String::startsWith($arg, "$")) {
return Environment::getVariable(substr($arg, 1));
} else {
return $arg;
}
}, $args);
}
public function universalFactory($options)
{
$arguments = isset($options["arguments"]) ? $this->processArguments($options["arguments"], $options["context"]) : array();
if (isset($options["class"])) {
if (!empty($arguments)) {
$object = ClassReflection::from($options["class"])->newInstanceArgs($arguments);
} else {
$class = $options["class"];
$object = new $class;
}
}
if (isset($options["factory"])) {
$object = call_user_func_array($options["factory"], $arguments);
}
if (isset($options["callMethods"])) {
foreach ($options["callMethods"] as $method => $args) {
call_user_func_array(array($object, $method), $this->processArguments($args, $options["context"]));
}
}
return $object;
}
}
Doctrine\ORM\EntityManager:
factory: ServiceFactories::createEntityManager
arguments: [$$database]
Nette\Security\IAuthenticator:
class: MyApp\Model\Authenticator
arguments: [%UserService]
UserService:
class: MyApp\Model\UserService
arguments: [%Doctrine\ORM\EntityManager]
ExampleService:
class: MyApp\Example
arguments: [$tempDir, true]
callMethods:
setMode: [$exampleMode]
setEntityManager: [%Doctrine\ORM\EntityManager]
setArray:
- [a, b, c]
@Vrtak-CZ
Copy link

Tajně doufám že něco podobného bude přímo v Nette

@mkoubik
Copy link

mkoubik commented Oct 13, 2010

Ta neon konfigurace je cool, ale neměl by tohle řešit spíš nějkej "NeonConfigurableContext implements IContext"?

@fprochazka
Copy link

Moc pěkně vymyšlené +1 ... kde se lobuje?

@Vrtak-CZ
Copy link

Tak jsem nad tím přemýšlel a souhlasím s mkoubik... Nehceš to sepsat jako RFC na Nette Fóru?

@dundee
Copy link

dundee commented Mar 26, 2011

Čau, vytvořil jsem něco podobného:

https://github.com/Dundee/Diphy/tree/nette

Rozdíl je hlavně v tom, že Diphy funguje ve většině případů bez konfigurace.

Příklady:

$di->getService('Example\Application');

Vytvoří instanci třídy Application. Pokud má třída závislosti, musí je vyjmenovat v konstruktoru. Diphy je pak při tvorbě instance sama doplní.

$di->getService('Foo\BarInterface');

Najde a vytvoří instanci implementace rozhraní BarInterface. Pokud má interface více implementací, je nutné zvolit jednu v konfiguraci.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment