diff --git a/controller/NotificationController.php b/controller/NotificationController.php index 6d702314c..638cb752c 100644 --- a/controller/NotificationController.php +++ b/controller/NotificationController.php @@ -327,13 +327,15 @@ class EchoNotificationController { $eventType = $event->getType(); + $res = ''; if ( isset( $wgEchoNotifications[$eventType] ) ) { + set_error_handler( array( __CLASS__, 'formatterErrorHandler' ), -1 ); try { $params = $wgEchoNotifications[$eventType]; $notifier = EchoNotificationFormatter::factory( $params ); $notifier->setOutputFormat( $format ); - return $notifier->format( $event, $user, $type ); + $res = $notifier->format( $event, $user, $type ); } catch ( Exception $e ) { $meta = array( 'id' => $event->getId(), @@ -344,11 +346,38 @@ class EchoNotificationController { ); wfDebugLog( __CLASS__, __FUNCTION__ . ": Error formatting " . FormatJson::encode( $meta ) ); MWExceptionHandler::logException( $e ); - return ''; } + restore_error_handler(); } - return Xml::tags( 'span', array( 'class' => 'error' ), - wfMessage( 'echo-error-no-formatter', $event->getType() )->escaped() ); + if ( $res ) { + 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; } } diff --git a/tests/NotificationFormatterTest.php b/tests/NotificationFormatterTest.php index 7c8b45726..4e3825262 100644 --- a/tests/NotificationFormatterTest.php +++ b/tests/NotificationFormatterTest.php @@ -206,19 +206,15 @@ class EchoNotificationFormatterTest extends MediaWikiTestCase { $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; - $params += $wgEchoNotifications[ $event->getType() ]; - $formatter = EchoNotificationFormatter::factory( $params ); - $formatter->setOutputFormat( $format ); - if ( $user === false ) { $user = User::newFromName('Notification-formatter-test'); } // 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 ) {