Yii Framework Forum: Add a 404 event to CWebApplication runController - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Add a 404 event to CWebApplication runController Rate Topic: -----

#1 User is offline   fr0d0z 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 86
  • Joined: 25-February 11
  • Location:CO, USA

Posted 01 May 2012 - 03:52 PM

Hi Guys,
I've been working on integrating Yii with some other systems (an old legacy system, WordPress, Drupal) where I'd like to have a controller action called before a 404 Exception is thrown. It would kind of be a catchAll controller action, but would be called after all other routes were tried.

I've looked through CWebApplication fairly thoroughly (catchAllRequest doesn't work, as it's used to redirect all pages to a temporary site down page or equivalent) and I think what I'm after is a new event added to CWebApplication's runController:


	public function runController($route)
	{
		if(($ca=$this->createController($route))!==null)
		{
			list($controller,$actionID)=$ca;
			$oldController=$this->_controller;
			$this->_controller=$controller;
			$controller->init();
			$controller->run($actionID);
			$this->_controller=$oldController;
		}
		else
+		{
+			$event=new CEvent($this,$route);
+			$this->on404Error($event);
+			if(!$event->handled)				
				throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
					array('{route}'=>$route===''?$this->defaultController:$route)));
+		}
	}

+	public function on404Error($event)
+	{
+		$this->raiseEvent('on404Error', $event);
+	}


This would allow a preloaded CApplicationComponent to catch 404 errors, try to run them through it's own routing schema and then either handle the event or let Yii handle it. Unlike using the errorComponent, this could catch the CHttpException before it's logged and handle it differently. Does that seem reasonable?

I know I can override CWebApplication for my app, but I wonder if this might be useful to have as part of the overall framework for other people to hook as well. Thoughts? Is there a better way to do this? I'm happy to submit a pull request on Github if you think it's worth it.
0

#2 User is offline   seb 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 230
  • Joined: 29-June 09

Posted 02 May 2012 - 06:35 AM

Look here (see attached pdf) or here (full article in russian).
I think configuring error handler component and setting error action to your controller action should work in your situation.
0

#3 User is offline   fr0d0z 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 86
  • Joined: 25-February 11
  • Location:CO, USA

Posted 02 May 2012 - 09:26 AM

I currently do set the error action, which does allow me to route to my default action. But my problem is that I'm getting errors in my logs (and via email) when in fact there are no errors. Thinking through it further (and thanks for the PDF, it was quite helpful), it looks like my problem is the placement of the Yii::log line in CApplication.php

A fix like this would patch it so I could catch 404 errors, try re-routing them through my own router and then not handle them if I couldn't resolve things properly:

	public function handleException($exception)
	{
		// disable error capturing to avoid recursive errors
		restore_error_handler();
		restore_exception_handler();

-		$category='exception.'.get_class($exception);
-		if($exception instanceof CHttpException)
-			$category.='.'.$exception->statusCode;
-		// php <5.2 doesn't support string conversion auto-magically
-		$message=$exception->__toString();
-		if(isset($_SERVER['REQUEST_URI']))
-			$message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI'];
-		if(isset($_SERVER['HTTP_REFERER']))
-			$message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER'];
-		$message.="\n---";
-		Yii::log($message,CLogger::LEVEL_ERROR,$category);

		try
		{
			$event=new CExceptionEvent($this,$exception);
			$this->onException($event);
			if(!$event->handled)
			{
+				$category='exception.'.get_class($exception);
+				if($exception instanceof CHttpException)
+					$category.='.'.$exception->statusCode;
+				// php <5.2 doesn't support string conversion auto-magically
+				$message=$exception->__toString();
+				if(isset($_SERVER['REQUEST_URI']))
+					$message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI'];
+				if(isset($_SERVER['HTTP_REFERER']))
+					$message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER'];
+				$message.="\n---";
+				Yii::log($message,CLogger::LEVEL_ERROR,$category);
				// try an error handler
				if(($handler=$this->getErrorHandler())!==null)
					$handler->handle($event);
				else
					$this->displayException($exception);
			}
		}
		catch(Exception $e)
		{
			$this->displayException($e);
		}


This would then allow the exception handler to disable the exception (as it had been successfully caught and dealt with) or let it fall through. Does that seem like a reasonble solution?
0

#4 User is offline   Maurizio Domba 

  • Yii - Yesss It Is !!!
  • Yii
  • Group: Yii Dev Team
  • Posts: 4,231
  • Joined: 12-October 09
  • Location:Croatia

Posted 02 May 2012 - 11:30 AM

Link to github issue for this - https://github.com/y.../yii/issues/669
Find more about me.... btw. Do you know your WAN IP?
0

#5 User is offline   hwm 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 14-December 12

Posted 18 March 2013 - 08:06 AM

I also was in need for a custom 404 handling (without triggering exceptions) for redirection purposes and have overridden CWebApplication for that purpose.

So I second the implementation of some hook function like suggested here by the original poster.

View Postfr0d0z, on 01 May 2012 - 03:52 PM, said:

Hi Guys,
I've been working on integrating Yii with some other systems (an old legacy system, WordPress, Drupal) where I'd like to have a controller action called before a 404 Exception is thrown. It would kind of be a catchAll controller action, but would be called after all other routes were tried.

I've looked through CWebApplication fairly thoroughly (catchAllRequest doesn't work, as it's used to redirect all pages to a temporary site down page or equivalent) and I think what I'm after is a new event added to CWebApplication's runController:


	public function runController($route)
	{
		if(($ca=$this->createController($route))!==null)
		{
			list($controller,$actionID)=$ca;
			$oldController=$this->_controller;
			$this->_controller=$controller;
			$controller->init();
			$controller->run($actionID);
			$this->_controller=$oldController;
		}
		else
+		{
+			$event=new CEvent($this,$route);
+			$this->on404Error($event);
+			if(!$event->handled)				
				throw new CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',
					array('{route}'=>$route===''?$this->defaultController:$route)));
+		}
	}

+	public function on404Error($event)
+	{
+		$this->raiseEvent('on404Error', $event);
+	}


This would allow a preloaded CApplicationComponent to catch 404 errors, try to run them through it's own routing schema and then either handle the event or let Yii handle it. Unlike using the errorComponent, this could catch the CHttpException before it's logged and handle it differently. Does that seem reasonable?

I know I can override CWebApplication for my app, but I wonder if this might be useful to have as part of the overall framework for other people to hook as well. Thoughts? Is there a better way to do this? I'm happy to submit a pull request on Github if you think it's worth it.

0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users