zend framework 2 set_exception_handler in ActionController - exception

I try use the "set_exception_handler" function for capture my ActionController exceptions.
Inside any view e.g. index.phtml this code works ok, the view show Helloooo.
<?php
namespace App;
echo $this->doctype();
class Fun {
static function exception_handler(\Exception $ex){
echo "Heloooo";
}
function method(){
set_exception_handler('App\Fun::exception_handler');
throw new \Exception('One Exception');
}
}
$f = new Fun();
$f->method();
I don't understand because the same code inside ActionController.php, set_exception_handler() doesn't catch the exception.
In this case the view shows the zend exception template with the "One Exception" message.
By the way, the exception stack doesn't show any Warning message, then I assume that set_exception_handler() parameter is well.
namespace App\Controller;
use Zend\....... //All namespaces used
class Fun {
static function exception_handler(\Exception $ex){
echo "Helloooo";
}
function method(){
set_exception_handler('App\Controller\Fun::exception_handler');
throw new \Exception('One Exception');
}
}
$f = new Fun();
$f->method();
class MainController extends AbstractActionController {
//The Controller Code (in this test it doesn't execute).
}
I think Zend Framework uses any technique for catching Controller exceptions in other level.
Please does somebody have any idea for do it?

I have to correct my previous post.
It seems to be a known bug of ZF. Have a look at this:
http://grokbase.com/t/php/php-bugs/128zn2emcx/php-bug-bug-62985-new-set-exception-handler-doesnt-work-from-command-line

Related

How to catch the 404 error with cakephp 3 in a productive environment

I want to catch all 404 errors (controller not found) in my new cake app. But I don't have a clue how.
Is there any configuration for that? Or must I catch the thrown error by myself? If so, where?
Here is one approach, that could work. Define you own error handler, that extends default ErrorHandler
<?php
// Custom Handler - goes in src/Error/AppError.php
namespace App\Error;
use Cake\Routing\Exception\MissingControllerException;
use Cake\Error\ErrorHandler;
class AppError extends ErrorHandler
{
public function _displayException($exception)
{
if ($exception instanceof MissingControllerException) {
// Here handle MissingControllerException by yourself
} else {
parent::_displayException($exception);
}
}
}
Then register this handler as default.
// Register handler in config/bootstrap.php
use App\Error\AppError;
$errorHandler = new AppError();
$errorHandler->register();
http://book.cakephp.org/3.0/en/development/errors.html

PHPUnit Mock Exception

I have a class which handles errors, including exceptions. If an exception is caught, I will pass the exception as an argument to my exception/error handler.
try {
someTrowingFnc();
} catch (\Exception $e) {
this->error->exception($e);
}
Now I want to unit test this error handler and mock the exception.
I am finding it hard to mock the exception so that I can control the exception message, file and line.
$exceptionMock = $this->getMock('Exception', array(
'getFile',
'getLine',
'getMessage',
'getTrace'
)); // Tried all mock arguments like disable callOriginalConstructor
$exceptionMock->expects($this->any())
->method('getFile')
->willReturn('/file/name');
$exceptionMock->expects($this->any())
->method('getLine')
->willReturn('3069');
$exceptionMock->expects($this->any())
->method('getMessage')
->willReturn('Error test');
The results of the code below always returns NULL
$file = $exception->getFile();
$line = $exception->getLine();
$msg = $exception->getMessage();
Is there a work-around to mock exceptions or am I just doing something wrong?
The Exception class methods that return the error details such as getFile() etc are defined/declared as final methods. And this is one limitation of PHPUnit currently in mocking methods that are protected, private, and final.
Limitations
Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.
As seen here: https://phpunit.de/manual/current/en/test-doubles.html
It's a bit of a hack, but try adding something like this to your TestCase:
/**
* #param object $object The object to update
* #param string $attributeName The attribute to change
* #param mixed $value The value to change it to
*/
protected function setObjectAttribute($object, $attributeName, $value)
{
$reflection = new \ReflectionObject($object);
$property = $reflection->getProperty($attributeName);
$property->setAccessible(true);
$property->setValue($object, $value);
}
Now you can change the values.
$exception = $this->getMock('Exception');
$this->setObjectAttribute($exception, 'file', '/file/name');
$this->setObjectAttribute($exception, 'line', 3069);
$this->setObjectAttribute($exception, 'message', 'Error test');
Of course, you haven't really mocked the class, though this can still be useful if you have a more complex custom Exception. Also you won't be able to count how many times the method is called, but since you were using $this->any(), I assume that doesn't matter.
It's also useful when you're testing how an Exception is handled, for example to see if another method (such as a logger) was called with the the exception message as a parameter
The throwException() in PHPUnit TestCase class can take any instance of Throwable as param.
Here is an example that should pass if you have try/catch in FileWriterToBeTested and will fail if you do not have try/catch:
$this->reader = $this->getMockBuilder(Reader::class)->getMock();
$this->reader->method('getFile')->will(static::throwException(new \Exception()));
$file = new FileWriterToBeTested($this->reader);
static::assertNull($file->getFile('someParamLikePath'));
tested class sample:
class FileWriterToBeTested
{
/**
* #var Reader
*/
private $reader;
public function __construct(Reader $reader): void
{
$this->reader = $reader;
}
/**
* #return Reader
*/
public function getFile(string $path): void
{
try {
$this->reader->getFile($path);
} catch (\Exception $e) {
$this->error->exception($e);
}
}
}

The _redirect() function in zend framework

I made a file in library/My/Utils/Utils.php. The content of the file is :
class My_Utils_Utils{
public function test(){
$this->_redirect('login');
}
}
This class is called from a layout; the problem is with the _redirect(); I get this error : The page isn't redirecting properly. My question is how call the _redirect() function from a class made by you in ZEND framework 1 .
Thanks in advance.
Use redirect() instead of _redirect(). Usage is:
$this->redirect(<action>, <controller>, <module>, <param>);
In your case $this->redirect('login'); should do the trick.
You can use the redirector action-helper, which you can get statically from the HelperBroker using:
// get the helper
$redirectHelper = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
// call methods on the helper
$redirect->gotoUrl('/some/url');
It should be noted, however, that the layout is considered part of the view layer. Typically, any checks that result in a redirect should probably take place earlier in the request dispatch-cycle, typically in a controller or in a front-controller plugin.
The _redirect function is provided by the class Zend_Controller_Action. You can fix this in two ways :
Extend Zend_Controller_Action and use _redirect
class My_Utils_Utils extends Zend_Controller_Action {
public function test(){
$this->_redirect('login');
}
}
in layout:
$request = Zend_Controller_Front::getInstance()->getRequest();
$response = Zend_Controller_Front::getInstance()->getResponse()
$util = new My_Utils_Utils($request, $response); // The constructor for Zend_Controller_Action required request and response params.
$util->test();
Use gotoUrl() function Zend_Controller_Action_Helper_Redirector::gotoUrl()
$redirector = new Zend_Controller_Action_Helper_Redirector();
$redirector->gotoUrl('login');
//in layout :
$util = new My_Utils_Utils();
$util->test();

Fatal error: Can't use function return value in write context SOMETIMES

I get so annoyed when I transfer websites from one machine to another and I get a bunch of errors, such as this case. But this one made it to my curiosity and this is why I'm asking a question. I have the following code:
namsepace MF;
class Box {
private static $dumpYard = array();
public static function get($name) {
return self::$dumpYard[$name];
}
public static function set($name, $value, $overwrite=false) {
if($overwrite || !isset(self::$dumpYard[$name])){
self::$dumpYard[$name] = $value;
}else{
if(DEBUG_MODE){
echo('Value for "'.$name.'" already set in box, can\'t overwrite');
}
}
}
}
So when my application gets to the following line on my LOCAL testing server:
if(!empty(\MF\Box::get('requestsSpam'))){
throw new \Exception('Please don\'t spam');
}
I get a Fatal error: Can't use function return value in write context. However this code does not throw an error on the actual hosting server of my website. How come is that?
empty() works only with a variable. It should be:
$result = \MF\Box::get('requestsSpam');
if(!empty($result)){
throw new \Exception('Please don\'t spam');
}
Why? empty() is a language construct and not a function. It will work only with declared variables, that's just how it is designed, no magic.

creating functions in CodeIgniter controllers

I have a CodeIgniter application, but one of my controllers must call a data processing function that I have also written myself. The only problem is I can't seem to figure out how to do this. Looking through the user guide it seems that I should put my function inside the class declaration, and prefix it with an underscore (_) so that it cannot be called via the url. However, this is not working. Here's an example of what I mean:
<?php
class Listing extends Controller
{
function index()
{
$data = "hello";
$outputdata['string'] = _dprocess($data);
$this->load->view('view',$outputdata);
}
function _dprocess($d)
{
$output = "prefix - ".$d." - suffix";
return $output
}
}
?>
The page keeps telling me I have a call to an undefined function _dprocess()
How do I call my own functions?
Thanks!
Mala
Edit:
I've gotten it to work by placing the function outside of the class declaration. Is this the correct way of doing it?
This line is creating problem for you:
$outputdata['string'] = _dprocess($data);
Replace with:
$outputdata['string'] = $this->_dprocess($data);