Introducing the ONLY search engine optimization software product that has been 100% PROVEN to dramatically increase your rankings in Google, Yahoo, and Bing. Get it now!
Ok, this is how I did it: As IoC Framework I used this component of the symfony framework (but I didn't download the latest version, I used an older one I used on projects before... keep that in mind! ). I added its classes under library/ioc/lib I added these init function in my Bootstrap.
Php in order to register the autoloader of the IoC framework: protected function _initIocFrameworkAutoloader() { require_once(APPLICATION_PATH . '/../library/Ioc/lib/sfServiceContainerAutoloader. Php'); sfServiceContainerAutoloader::register(); } Next, I made some settings in application.
Ini which set the path to the wiring xml and allow to disable automatic dependency injection e. G. In unit tests: ioc.controllers.
WiringXml = APPLICATION_PATH "/objectconfiguration/controllers. Xml" ioc.controllers. EnableIoc = 1 Then, I created a custom builder class, which extends sfServiceContainerBuilder and put it under library/MyStuff/Ioc/Builder.
Php In this test project I keep all my classes under library/MyStuff class MyStuff_Ioc_Builder extends sfServiceContainerBuilder { public function initializeServiceInstance($service) { $serviceClass = get_class($service); $definition = $this->getServiceDefinition($serviceClass); foreach ($definition->getMethodCalls() as $call) { call_user_func_array(array($service, $call0), $this->resolveServices($this->resolveValue($call1))); } if ($callable = $definition->getConfigurator()) { if (is_array($callable) && is_object($callable0) && $callable0 instanceof sfServiceReference) { $callable0 = $this->getService((string) $callable0); } elseif (is_array($callable)) { $callable0 = $this->resolveValue($callable0); } if (!is_callable($callable)) { throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable. ', get_class($service))); } call_user_func($callable, $service); } } } Last, I created a custom controller class in library/MyStuff/Controller. Php which all my controllers inherit from: class MyStuff_Controller extends Zend_Controller_Action { /** * @override */ public function dispatch($action) { // NOTE: the application settings have to be saved // in the registry with key "config" $config = Zend_Registry::get('config'); if($config'ioc''controllers''enableIoc') { $sc = new MyStuff_Ioc_Builder(); $loader = new sfServiceContainerLoaderFileXml($sc); $loader->load($config'ioc''controllers''wiringXml'); $sc->initializeServiceInstance($this); } parent::dispatch($action); } } What this basically does is using the IoC Framework in order to initialize the already created controller instance ( $this ).
Simple tests I did seemed to do what I want... let´s see how this performs in real life situations. ;) It´s still monkey patching somehow, but the Zend Framework doesn´t seem to provide a hook where I can create the controller instance with a custom controller factory, so this is the best I came up with.
Ok, this is how I did it: As IoC Framework I used this component of the symfony framework (but I didn't download the latest version, I used an older one I used on projects before... keep that in mind! ). I added its classes under /library/ioc/lib/.
I added these init function in my Bootstrap. Php in order to register the autoloader of the IoC framework: protected function _initIocFrameworkAutoloader() { require_once(APPLICATION_PATH . '/../library/Ioc/lib/sfServiceContainerAutoloader.
Php'); sfServiceContainerAutoloader::register(); } Next, I made some settings in application. Ini which set the path to the wiring xml and allow to disable automatic dependency injection e. G.In unit tests: ioc.controllers.
WiringXml = APPLICATION_PATH "/objectconfiguration/controllers. Xml" ioc.controllers. EnableIoc = 1 Then, I created a custom builder class, which extends sfServiceContainerBuilder and put it under /library/MyStuff/Ioc/Builder.php.
In this test project I keep all my classes under /library/MyStuff/. Class MyStuff_Ioc_Builder extends sfServiceContainerBuilder { public function initializeServiceInstance($service) { $serviceClass = get_class($service); $definition = $this->getServiceDefinition($serviceClass); foreach ($definition->getMethodCalls() as $call) { call_user_func_array(array($service, $call0), $this->resolveServices($this->resolveValue($call1))); } if ($callable = $definition->getConfigurator()) { if (is_array($callable) && is_object($callable0) && $callable0 instanceof sfServiceReference) { $callable0 = $this->getService((string) $callable0); } elseif (is_array($callable)) { $callable0 = $this->resolveValue($callable0); } if (!is_callable($callable)) { throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service))); } call_user_func($callable, $service); } } } Last, I created a custom controller class in /library/MyStuff/Controller. Php which all my controllers inherit from: class MyStuff_Controller extends Zend_Controller_Action { /** * @override */ public function dispatch($action) { // NOTE: the application settings have to be saved // in the registry with key "config" $config = Zend_Registry::get('config'); if($config'ioc''controllers''enableIoc') { $sc = new MyStuff_Ioc_Builder(); $loader = new sfServiceContainerLoaderFileXml($sc); $loader->load($config'ioc''controllers''wiringXml'); $sc->initializeServiceInstance($this); } parent::dispatch($action); } } What this basically does is using the IoC Framework in order to initialize the already created controller instance ($this).
Simple tests I did seemed to do what I want... let´s see how this performs in real life situations. ;) It´s still monkey patching somehow, but the Zend Framework doesn´t seem to provide a hook where I can create the controller instance with a custom controller factory, so this is the best I came up with...
– takeshin Sep 7 '10 at 11:02 @takeshin good call, it´ll be better to initialize the container in the bootstrap file. Would you suggest to put the instance in Zend_Registry? I am just learning ZF, so it´s very likely that the code I showed could be optimised.
Looking forward to your suggestions and I´ll update the code later along with my XML wiring code (dont have time right now... work, work, work ;)). – Max Sep 7 '10 at 14:57 I don't use Registry at all. In the bootstrap make _initSth(){return $object} and the $object will be an application resource which you may get anywhere by: $boostrap->getResource('sth'), eg.In the controller: $this->getInvokeArg('bootstrap')->getResource('sth') – takeshin Sep 7 '10 at 16:33.
Logic to models First of all, it's worth to mention, that controllers should need only functional tests, though all the logic belongs to models. My implementation Here is an excerpt from my Action Controller implementation, which solves the following problems: allows inject any dependency to actions validates the action parameters, e.g. You may not pass array in $_GET when integer is expected My full code allows also to generate canonical URL (for SEO or unique page hash for stats) based or required or handled action params. For this, I use this abstract Action Controller and custom Request object, but this is not the case we discuss here.
Obviously, I use Reflections to automatically determine action parameters and dependency objects. This is a huge advantage and simplifies the code, but also has an impact in performance (minimal and not important in case of my app and server), but you may implement some caching to speed it up. Calculate the benefits and the drawbacks, then decide.
DocBlock annotations are becoming a pretty well known industry standard, and parsing it for evaluation purposes becomes more popular (e.g. Doctrine 2). I used this technique for many apps and it worked nicely. Writing this class I was inspired by Actions, now with params!
And Jani Hartikainen's blog post.So, here is the code: getInvokeArg('useCaseSensitiveActions')) { trigger_error( 'Using case sensitive actions without word separators' . 'is deprecated; please do not rely on this "feature"' ); return true; } if (method_exists($this, $action)) { return true; } return false; } /** * * @param string $action * @return array of Zend_Reflection_Parameter objects */ protected function _actionReflectionParams($action) { $reflMethod = new Zend_Reflection_Method($this, $action); $parameters = $reflMethod->getParameters(); return $parameters; } /** * * @param Zend_Reflection_Parameter $parameter * @return string * @throws Your_Controller_Action_Exception when required @param is missing */ protected function _getParameterType(Zend_Reflection_Parameter $parameter) { // get parameter type $reflClass = $parameter->getClass(); if ($reflClass instanceof Zend_Reflection_Class) { $type = $reflClass->getName(); } else if ($parameter->isArray()) { $type = 'array'; } else { $type = $parameter->getType(); } if (null === $type) { throw new Your_Controller_Action_Exception( sprintf( "Required @param DocBlock not found for '%s'", $parameter->getName() ) ); } return $type; } /** * * @param Zend_Reflection_Parameter $parameter * @return mixed * @throws Your_Controller_Action_Exception when required argument is missing */ protected function _getParameterValue(Zend_Reflection_Parameter $parameter) { $name = $parameter->getName(); $requestValue = $this->getRequest()->getParam($name); if (null! == $requestValue) { $value = $requestValue; } else if ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); } else { if (!$parameter->isOptional()) { throw new Your_Controller_Action_Exception( sprintf("Missing required value for argument: '%s'", $name)); } $value = null; } return $value; } /** * * @param mixed $value */ protected function _fixValueType($value, $type) { if (in_array($type, $this->_basicTypes)) { settype($value, $type); } return $value; } /** * Dispatch the requested action * * @param string $action Method name of action * @return void */ public function dispatch($action) { $request = $this->getRequest(); // Notify helpers of action preDispatch state $this->_helper->notifyPreDispatch(); $this->preDispatch(); if ($request->isDispatched()) { // preDispatch() didn't change the action, so we can continue if ($this->_hasAction($action)) { $requestArgs = array(); $dependencyObjects = array(); $requiredArgs = array(); foreach ($this->_actionReflectionParams($action) as $parameter) { $type = $this->_getParameterType($parameter); $name = $parameter->getName(); $value = $this->_getParameterValue($parameter); if (!in_array($type, $this->_basicTypes)) { if (!is_object($value)) { $value = new $type($value); } $dependencyObjects$name = $value; } else { $value = $this->_fixValueType($value, $type); $requestArgs$name = $value; } if (!$parameter->isOptional()) { $requiredArgs$name = $value; } } // handle canonical URLs here $allArgs = array_merge($requestArgs, $dependencyObjects); // dispatch the action with arguments call_user_func_array(array($this, $action), $allArgs); } else { $this->__call($action, array()); } $this->postDispatch(); } $this->_helper->notifyPostDispatch(); } } To use this, just: Your_FineController extends Your_Controller_Action {} and provide annotations to actions, as usual (at least you already should ;).E.g.
/** * @param int $id Mandatory parameter * @param string $sorting Not required parameter * @param Your_Model_Name $model Optional dependency object */ public function indexAction($id, $sorting = null, Your_Model_Name $model = null) { // model has been already automatically instantiated if null $entry = $model->getOneById($id, $sorting); } (DocBlock is required, however I use Netbeans IDE, so the DocBlock is automatically generated based on action arguments).
Hm, interesting approach using reflection to extract the arguments of the action method... thanks! – Max Sep 6 '10 at 7:14.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.