Re: [fw-general] Re: Zend_Controller_Action::init() (Was: SVN 2077: Getting parameters from route)

2006-12-06 Thread Matthew Weier O'Phinney
-- Nick Lo [EMAIL PROTECTED] wrote
(on Wednesday, 06 December 2006, 03:09 PM +1100):
 Aha, now I get it ...so what I CAN do is:

snip -- code examples

 So in short init() is a convenience method which is fine. 

Correct. It's to make it easier on you, the developer, so you don't have
to write out that nasty __construct() line. :-)

 I was just uncomfortable with the idea of being forced to use it on
 the basis that things otherwise broke (which they don't - my mistake)
 and that I may forget to properly initialise the parent class.
 
 Thanks very much for your detailed (and patient) responses, I now  
 follow it a lot more clearly.

No problem! Glad I was able to clarify things.

 -- Nick Lo [EMAIL PROTECTED] wrote
 (on Wednesday, 06 December 2006, 01:00 PM +1100):
 Hi Matthew,
 
 init() happens at object instantiation, which happens before
 preDispatch() -- it's basically provided so that you don't need to
 override the constructor, and thus possibly forget to set the  
 request,
 response, and other parameters (as you discovered the hard way).
 
 It does seem like having init() as a means to bypass the constructor
 and also having preDispatch() is possibly a little unintuitive.
 Surely init() is a constructor of sorts?
 
 It's not meant to bypass the constructor; it's meant as a means to  
 allow
 further instantiation actions without needing to override the  
 constructor.
 
 Matt Ratzloff asked why not declare it final? My answer to this is
 backwards compatability; by not declaring it final, developers instead
 can fix their classes as they start needing some of the functionality,
 such as access to the request object, instead of having their apps  
 break
 entirely due to the constructor now being final. (There were a lot of
 complaints about this.)
 
 In theory I can set the request and response
 
 $controller-setRequest( new Zend_Controller_Request_Http );
 $controller-setResponse( new Zend_Controller_Response_Http );
 
 ...as I do the router...
 
 $controller-setRouter($router);
 
 This latter is only in the front controller.
 
 
 ...but it will still be required to specified in the constructor of
 classes overriding __construct...
 
 parent::__construct( new Zend_Controller_Request_Http, new
 Zend_Controller_Response_Http );
 
 ...however at that point the parameters will not be available.
 
 Umm... yes, they will, if you define your constructor to follow
 Zend_Controller_Action's prototype:
 
 public function __construct(
 Zend_Controller_Request_Abstract $request = null,
 Zend_Controller_Response_Abstract $response = null,
 array $invokeArgs = null)
 {}
 
 then simply do this:
 
 public function __construct(...)
 {
 parent::__construct($request, $response, $invokeArgs);
 
 // ...
 }
 
 It seems that if we have to follow the init() path the manual is
 going to have to say something like...
 
  If you subclass Zend_Controller_Action you should not override the
 constructor instead setup code should go in the init() method
 
 It does say that. In the current manual from subversion:
 
 While you may override the constructor, we suggest putting any
 initialization handling into init() to ensure the request and
 response objects are properly registered.
 
 In other words it will need to be a warning. That is where I feel
 that init() is unintuitive and most people (I say with hesitation
 being a self elected representative) would expect to go with the
 constructor for this task.
 
 Note also that I didn't forget to set the request and response
 objects when I overrode the constructor, rather that when I did set
 them in the subclass no parameters were available in the controller.
 
 You set them improperly, though. You created *new* objects, instead of
 simply passing in the parameters that were passed to your constructor.
 
 Theoretically, if something goes wrong during the initialization
 sequence, you could throw an exception, in which case the
 preDispatch()
 will not be called -- this may be handy so that you can, for  
 instance,
 setup your models, etc., and, if unavailable, prevent the action  
 from
 dispatching. preDispatch() might then actually use the models to do
 some
 determination of whether or not to skip the current action.
 
 I follow the theory and I'd be interested in hearing how others are
 using preDispatch and whether their use really does differentiate  
 init
 () from preDispatch() in the way you mention.
 
 Here's how I'm using it in one of my applications. I have this in a
 Zend_Controller_Action subclass from which my other classes then  
 derive:
 
 public function init()
 {
 // Loads the model based on the current action, which will  
 throw
 // an exception if there are issues
 $this-loadModel();
 
 // Load up authentication and start it. Again, throws an
 // exception if there are issues
 $this-getAuth()-start();
 }
 
 Then, 

Re: [fw-general] Re: Zend_Controller_Action::init() (Was: SVN 2077: Getting parameters from route)

2006-12-05 Thread Nick Lo

Aha, now I get it ...so what I CAN do is:

class IndexController extends Zend_Controller_Action
{
public function __construct(
Zend_Controller_Request_Abstract $request = null,
Zend_Controller_Response_Abstract $response = null,
array $invokeArgs = null)
{
parent::__construct($request, $response, $invokeArgs);
 do other stuff
}

}

...then...

class ArticlesController extends IndexController
{
public function __construct(
Zend_Controller_Request_Abstract $request = null,
Zend_Controller_Response_Abstract $response = null,
array $invokeArgs = null)
{
parent::__construct($request, $response, $invokeArgs);
Zend_Db_Table::setDefaultAdapter( $this-_database );
 do other stuff
}
}

However, the recommended approach is...

class IndexController extends Zend_Controller_Action
{
public function init()
{
do stuff
}
}

...then...

class ArticlesController extends IndexController
{
public function init()
{
parent::init();
do stuff
}
}

So in short init() is a convenience method which is fine. I was just  
uncomfortable with the idea of being forced to use it on the basis  
that things otherwise broke (which they don't - my mistake) and that  
I may forget to properly initialise the parent class.


Thanks very much for your detailed (and patient) responses, I now  
follow it a lot more clearly.


Nick


-- Nick Lo [EMAIL PROTECTED] wrote
(on Wednesday, 06 December 2006, 01:00 PM +1100):

Hi Matthew,


init() happens at object instantiation, which happens before
preDispatch() -- it's basically provided so that you don't need to
override the constructor, and thus possibly forget to set the  
request,

response, and other parameters (as you discovered the hard way).


It does seem like having init() as a means to bypass the constructor
and also having preDispatch() is possibly a little unintuitive.
Surely init() is a constructor of sorts?


It's not meant to bypass the constructor; it's meant as a means to  
allow
further instantiation actions without needing to override the  
constructor.


Matt Ratzloff asked why not declare it final? My answer to this is
backwards compatability; by not declaring it final, developers instead
can fix their classes as they start needing some of the functionality,
such as access to the request object, instead of having their apps  
break

entirely due to the constructor now being final. (There were a lot of
complaints about this.)


In theory I can set the request and response

$controller-setRequest( new Zend_Controller_Request_Http );
$controller-setResponse( new Zend_Controller_Response_Http );

...as I do the router...

$controller-setRouter($router);


This latter is only in the front controller.



...but it will still be required to specified in the constructor of
classes overriding __construct...

parent::__construct( new Zend_Controller_Request_Http, new
Zend_Controller_Response_Http );

...however at that point the parameters will not be available.


Umm... yes, they will, if you define your constructor to follow
Zend_Controller_Action's prototype:

public function __construct(
Zend_Controller_Request_Abstract $request = null,
Zend_Controller_Response_Abstract $response = null,
array $invokeArgs = null)
{}

then simply do this:

public function __construct(...)
{
parent::__construct($request, $response, $invokeArgs);

// ...
}


It seems that if we have to follow the init() path the manual is
going to have to say something like...

 If you subclass Zend_Controller_Action you should not override the
constructor instead setup code should go in the init() method


It does say that. In the current manual from subversion:

While you may override the constructor, we suggest putting any
initialization handling into init() to ensure the request and
response objects are properly registered.


In other words it will need to be a warning. That is where I feel
that init() is unintuitive and most people (I say with hesitation
being a self elected representative) would expect to go with the
constructor for this task.

Note also that I didn't forget to set the request and response
objects when I overrode the constructor, rather that when I did set
them in the subclass no parameters were available in the controller.


You set them improperly, though. You created *new* objects, instead of
simply passing in the parameters that were passed to your constructor.


Theoretically, if something goes wrong during the initialization
sequence, you could throw an exception, in which case the
preDispatch()
will not be called -- this may be handy so that you can, for  
instance,
setup your models, etc., and, if unavailable, prevent the action  
from

dispatching. preDispatch() might then actually use the models to do
some
determination of whether or not to