Catch catchable fatal errors when formatting echo notifications

Change-Id: Ieaf02ece716802309e85ed0e32a0a15fcd24c50d
This commit is contained in:
Erik Bernhardson 2014-02-06 15:06:54 -08:00
parent 8530a36952
commit fcd4f67c93
2 changed files with 35 additions and 10 deletions

View file

@ -327,13 +327,15 @@ class EchoNotificationController {
$eventType = $event->getType(); $eventType = $event->getType();
$res = '';
if ( isset( $wgEchoNotifications[$eventType] ) ) { if ( isset( $wgEchoNotifications[$eventType] ) ) {
set_error_handler( array( __CLASS__, 'formatterErrorHandler' ), -1 );
try { try {
$params = $wgEchoNotifications[$eventType]; $params = $wgEchoNotifications[$eventType];
$notifier = EchoNotificationFormatter::factory( $params ); $notifier = EchoNotificationFormatter::factory( $params );
$notifier->setOutputFormat( $format ); $notifier->setOutputFormat( $format );
return $notifier->format( $event, $user, $type ); $res = $notifier->format( $event, $user, $type );
} catch ( Exception $e ) { } catch ( Exception $e ) {
$meta = array( $meta = array(
'id' => $event->getId(), 'id' => $event->getId(),
@ -344,11 +346,38 @@ class EchoNotificationController {
); );
wfDebugLog( __CLASS__, __FUNCTION__ . ": Error formatting " . FormatJson::encode( $meta ) ); wfDebugLog( __CLASS__, __FUNCTION__ . ": Error formatting " . FormatJson::encode( $meta ) );
MWExceptionHandler::logException( $e ); MWExceptionHandler::logException( $e );
return '';
} }
restore_error_handler();
} }
return Xml::tags( 'span', array( 'class' => 'error' ), if ( $res ) {
wfMessage( 'echo-error-no-formatter', $event->getType() )->escaped() ); return $res;
} else {
return Xml::tags( 'span', array( 'class' => 'error' ),
wfMessage( 'echo-error-no-formatter', $event->getType() )->escaped() );
}
}
/**
* INTERNAL. Must be public to be callable by the php error handling methods.
*
* Converts E_RECOVERABLE_ERROR, such as passing null to a method expecting
* a non-null object, into exceptions.
*/
public static function formatterErrorHandler( $errno, $errstr, $errfile, $errline ) {
if ( $errno !== E_RECOVERABLE_ERROR ) {
return false;
}
throw new CatchableFatalErrorException( $errno, $errstr, $errfile, $errline );
}
}
class CatchableFatalErrorException extends MWException {
public function __construct( $errno, $errstr, $errfile, $errline ) {
parent::__construct( "Catchable fatal error: $errstr", $errno );
// inherited protected variables from \Exception
$this->file = $errfile;
$this->line = $errline;
} }
} }

View file

@ -206,19 +206,15 @@ class EchoNotificationFormatterTest extends MediaWikiTestCase {
$this->assertContains( $expect, $this->format( $event, 'html' ) ); $this->assertContains( $expect, $this->format( $event, 'html' ) );
} }
protected function format( EchoEvent $event, $format, $user = false, $type = 'web', array $params = array() ) { protected function format( EchoEvent $event, $format, $user = false, $type = 'web' ) {
global $wgEchoNotifications; global $wgEchoNotifications;
$params += $wgEchoNotifications[ $event->getType() ];
$formatter = EchoNotificationFormatter::factory( $params );
$formatter->setOutputFormat( $format );
if ( $user === false ) { if ( $user === false ) {
$user = User::newFromName('Notification-formatter-test'); $user = User::newFromName('Notification-formatter-test');
} }
// Notification users can not be anonymous, use a fake user id // Notification users can not be anonymous, use a fake user id
return $formatter->format( $event, $user, $type ); return EchoNotificationController::formatNotification( $event, $user, $format, $type );
} }
protected function mockEvent( $type, array $extra = array(), Revision $rev = null ) { protected function mockEvent( $type, array $extra = array(), Revision $rev = null ) {