PHPUnit and Zend: Testing a function on a controller? - zend-framework

I have a controller called "SiteController". On it there is a normal indexAction which displays the frontpage. It's fairly easy to test this, but how would I test another function that is NOT an action with parameters. Let's say I have a function called "sendMail($to, $message)". How do I test that?
<?php
class ControllerTest extends Zend_Test_PHPUnit_ControllerTestCase
{
public function testShowCallsServiceFind()
{
$this->dispatch('/index'); // dont care about this...
// what I need is a way to do this:
$res = $controller->sendMail("bla", "bla"); // so that I can test sendMail?
}
}
How can I test sendMail?

You dont actually need to call the dispatch method, you can new up a controller object and call methods directly:
$controller = new \My\Controller();
$actual_result = $controller->sendMail($params);
$this->assertEquals($expected_result, $actual_result);
Be careful though, you'll need to 'mock' your dependencies so you don't actually send a real email when you run your tests! http://phpunit.de/manual/3.0/en/mock-objects.html

Related

How to use addClause() outside setup() in Laravel Backpack?

Say we have the UserCrudController like so:
public function setup()
{
// ...
// This works:
$this->crud->addClause('active');
// ...
}
The addClause() works fine. Now say we add it outside the setup():
public function posts()
{
// ...
// This DOES NOT work:
$this->crud->addClause('active');
// ...
}
Calling addClause() outside like this works, but if its inside a logic, it does not:
public function setup()
{
// This works:
$this->applyQueries();
}
private function applyQueries()
{
// This works:
$this->crud->addClause('active');
// This DOES NOT work:
if (true)
$this->crud->addClause('active');
}
Recap: I need to call addClause() from another function and inside a logic. How?
If you're creating a custom method, there's no way for Backpack to know what you want to do inside that method. Only what you write inside it will happen, in addition to what's in setup(), which is called in the __constructor().
Depending on your use case (list/create/edit/preview/etc), I recommend you take a look at the logic inside Backpack's CrudController. The methods there contain the logic for the operations above, and do use the addClause(). Copy-paste whatever you need to your posts() method. You'll basically be able to use the query where the clauses have been added by taking advantage of the $this->crud object, so the query would be $this->crud->query.

How to run same lines in all controllers init() function?

I need same 2 lines in all my controllers, each controller have its own init logic, but these two lines are common for all of them.
public function init()
{
$fm =$this->_helper->getHelper('FlashMessenger');
$this->view->messages = $fm->getMessages();
}
How can I avoid repeat code ?
Update:
Ok, the FlashMessenger was only an example, let's say I need write a log line in every action except for 'someAction' # 'someController'. So the new common lines should be.
$this->logger = new Zend_Log();
$writer = new Zend_Log_Writer_Stream(APPLICATION_PATH.'/../logs/log.txt');
$this->logger->addWriter($writer);
$this->logger->log('Some Message',Zend_Log::DEBUG);
The question is, where should I place these lines in order to avoid repeat them in all init() of each controller.
These lines should be placed at bootstrap?. If so: How can skip log lines for 'someAction'.
Or should I implement a 'BaseController' and make all my controller extend from it. If so: How can I Autoload it? (Fatal error: Class 'BaseController' not found) .
Just subclass the controller:
class Application_ControllerAction extends Zend_Controller_Action {
public function init()
{
$fm =$this->_helper->getHelper('FlashMessenger');
$this->view->messages = $fm->getMessages();
}
}
class IndexController extends Application_ControllerAction {
}
You may also achieve the same writing Controller Plugin.
Edit:
Front controller plugins are executed on each request, just like the Controllers and have the same hook methods:
routeStartup(): prior to routing the request
routeShutdown(): after routing the request
dispatchLoopStartup(): prior to entering the dispatch loop
preDispatch(): prior to dispatching an individual action
postDispatch(): after dispatching an individual action
dispatchLoopShutdown(): after completing the dispatch loop
I addition, you may check controller params to execute the code only on selected requests:
if ('admin' == $this->getRequest()->getModuleName()
&& 'update' == $this->getRequest()->getActionName() ) …
You can access your flash messages through (you dont need to send anything from your controller to your view, it's all automated)
$fm = new Zend_Controller_Action_Helper_FlashMessenger();
Zend_Debug::dump($fm->getMessages());
in you view, i would also recommand that you encapsulate this code in a view helper like it is shown on this site http://grummfy.be/blog/191
In your bootstrap:
protected function _initMyActionHelpers() {
$fm = new My_Controller_Action_Helper_FlashMessenger();
Zend_Controller_Action_HelperBroker::addHelper($fm);;
}
How can I avoid repeat code ?
Write your own custom controller, implement that in init method of that controller, and then extend all controllers in your app from your custom controller.
But approach with separate view helper as #Jeff mentioned (look at link) is often taken as a better solution.
In your controller do only:
$this->_helper->flashMessanger('My message');
and view helper will do the rest.
It's not the reason for creating new custom controller. Just add this line to all you init() methods.
$this->view->messages = $this->_helper->getHelper('FlashMessenger')->getMessages();

How to use Zend Framework's Partial Loop with Objects

I am quite confused how to use partialLoop
Currently I use
foreach ($childrenTodos as $childTodo) {
echo $this->partial('todos/_row.phtml', array('todo' => $childTodo));
}
$childrenTodos is a Doctrine\ORM\PersistantCollection, $childTodo is a Application\Models\Todo
I tried doing
echo $this->partialLoop('todos/_row.phtml', $childrenTodos)
->setObjectKey('Application\Models\Todo');
But in the partial when I try to access properties/functions of my Todo class, I cant seem to get them always ending up with either call to undefined method Zend_View::myFunction() when I use $this->myFunction() in the partial or if I try $this->todo->getName() I get "Call to a member function getName() on a non-object". How do I use partialLoops?
Try this
echo $this->partialLoop('todos/_row.phtml', $childrenTodos)
->setObjectKey('object');
Then in your partial you can access the object like this
$this->object
object is the name of the variable that an object will be assigned to
You can also do this once in your Bootstrap or other initialization class if you have access to the view object like so
protected function initPartialLoopObject()
{
$this->_view->partialLoop()->setObjectKey('object');
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
$viewRenderer->setView($this->_view);
}
I also had "Call to function on non object" error when trying suggested syntax, seems like they've changed something on later versions of Zend Framework. The following works for me on ZF1.12:
echo $this->partialLoop()
->setObjectKey('object')
->partialLoop('todos/_row.phtml', $childrenTodos);

Zend: Quick and succinct way of inserting custom HTML into a Zend_Form?

Is there some method that accepts inserting custom html without having to actually add form controls, even if they're hidden and making my html a decorator?
I'm looking for something like:
$this->addCustomElement( array(
'div',
'body' => '<p>inner text</p>'
) );
I need something short and quick, I don't want to create a new class or something overkill.
Well it's really as simple as this:
$note = new Zend_Form_Element('note');
$note->helper = 'formNote';
$note->setValue('<b>hi</b>');
$form->addElement($note);
But the problem is that when you submit the form, the form calls $note->isValid(), which overrides the value, so if there are errors with the form, the next time you display it, the custom HTML won't be shown. There are two easy ways to fix this, the first is to override isValid() in your Form class like this:
public function isValid($data)
{
$note = $this->note->getValue();
$valid = parent::isValid($data);
$this->note->setValue($note);
return $valid;
}
But personally I find this kinda hackish way, and prefer the second option. That is to write a very simple class (this should really be part of Zend itself, I have no idea why it isn't, since it includes a formNote view helper, but no element that uses it):
class My_Form_Element_Note extends Zend_Form_Element_Xhtml
{
public $helper = 'formNote';
public function isValid($value, $context = null) { return true; }
}
Then you just have to do:
$note = new My_Form_Element_Note('note');
$note->setValue('<b>hi</b>');
$form->addElement($note);
And everything will just work.
Other options include doing some black magic with decorators, but I really recommend you to not go down that path.
Also note the AnyMarkup Decorator.

Wordpress: Accessing A Plugin's Function From A Theme

I'm trying to add some functionality from a plugin I have made into a Wordpress theme but I am having little joy. The documentation doesn't really help me solve the problem so perhaps someone here can help.
I have a plugin in Wordpress that is activated and working fine. The class for this plugin has a function called generateHtml which I would like to access from a Wordpress Theme. But whatever I try, I cannot seem to access my plugin's code.
Can either give me a summary of what I need to do to get a theme accessing code from a plugin and/or point out there I am going wrong in my code:
Plugin:
<?php
/** Usual comments here **/
if (!class_exists("ImageRotator")) {
class ImageRotator {
private $uploadPath = '';
private $pluginPath = '';
private $options;
function __construct() {
$this->uploadPath = dirname(__file__).'\\uploads\\';
// add_shortcode('imagerotator', array(&$this, 'generateHtml'));
}
// Various functions for plugin
function generateHtml() {
echo '<p>Hello World</p>';
}
}
}
/**
* Create instance of image rotator
*/
$imageRotator = new ImageRotator();
/**
* Create actions & filters for Wordpress
*/
if (isset($imageRotator)) {
// Actions
add_action('admin_menu', array(&$imageRotator, 'createMenu'));
add_action('admin_init', array(&$imageRotator, 'registerSettings'));
add_action('imagerotator_show', array(&$imageRotator, 'generateHtml'));
}
Portion from theme header page:
<?php if (isset($imageRotator)) {
$imageRotator->generateHtml();
} else if (isset($ImageRotator)) {
print_r($ImageRotator);
} else {
echo '<p>Nope!</p>';
}
if (function_exists("imagerotator_show")) {
echo 'Function found';
} else {
echo 'Function NOT found';
}
?>
Currently all I ever see is "Nope" and "Function NOT found". Thanks for any input.
Lee,
For starters, "imagerotator_show" is not a function; it's the name of a type of action. When you use the add_action() function, Wordpress just adds your method to the list of functions/methods to call when a particular action is triggered. Thus your second test will always respond with 'Function NOT found'.
The most likely cause of the first problem is failing to declare the method you want to call as a public method. You're also making the code harder than it needs to be.
The best practice I've seen for declaring methods and registering hooks from a class looks something like this:
if ( ! class_exists( 'Foo' ) ):
class Foo {
function __construct() {
add_action( 'hook_name', array( &$this, 'my_hook_implementation' ) );
}
function my_hook_implementation() {
// does something
}
public function my_special_method() {
// does something else
}
}
if ( class_exists( 'Foo' ) ):
$MyFoo = new Foo();
This allows your class to keep all of its implementation details private. When you need to call my_special_method(), you do it as follows:
$MyFoo->my_special_method();
#andrew since I can't comment I thought I would answer your ancillary question. See:
http://net.tutsplus.com/tutorials/wordpress/create-wordpress-plugins-with-oop-techniques/
Where it is explained that when defining a callback function from an object you have to use the array function. It's basically saying get the function 'my_hook_implementation' from the object $this and use it as the callback parameter to the add action hook. It is because you defined the function within the scope of the object and you have to define the scope in order for PHP to know what function you are talking about. The scope being the object referred to by the variable $this.
You just need to use do_action() function, inside your theme.
If you want the function generateHtml to appears inside your header.php you just need to open the header.php file and paste <?php do_action('imagerotator_show'); ?> where you want and then your function will be called there.