-
-
Save janmarek/623720 to your computer and use it in GitHub Desktop.
| 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] |
Ta neon konfigurace je cool, ale neměl by tohle řešit spíš nějkej "NeonConfigurableContext implements IContext"?
Moc pěkně vymyšlené +1 ... kde se lobuje?
Tak jsem nad tím přemýšlel a souhlasím s mkoubik... Nehceš to sepsat jako RFC na Nette Fóru?
Č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.
Tajně doufám že něco podobného bude přímo v Nette