Error handling with MVC and PHP4 ideas

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Nathaniel
Forum Contributor
Posts: 396
Joined: Wed Aug 31, 2005 5:58 pm
Location: Arkansas, USA

Error handling with MVC and PHP4 ideas

Post by Nathaniel »

Hi guys,

I've been trying to understand MVC with sites like phpPatterns. I haven't got any books yet, but I think I have the basic idea. So anyway, below is my attempt at an MVC for an update profile script. I decided the Front Controller is Apache coupled with mod_rewrite, and the Page Controller is update-profile.php coupled with an UpdateProfileController class.

I don't think I could have gone wrong with my design, since it's so shallow right now, but I'm frustrated with how to deal with errors. The code right now:

Code: Select all

<?PHP
#update-profile.php
$request = new Request(); //give it post, get, whatnot
$response = new Response();
$controller = new UpdateProfileController();

if ( isAnError( $error = $controller->checkUserPermissions( 
	new UserPermissions( $request->getCredentials() ) 
	) )
   )
{
	$response->setHeader( $error->getHeader() );
	$response->setContent( $error->getView() );
	$response->send();
	exit;
}

$controller->setModel( 
	new UpdateProfileModel( $request->getPostData() ) 
);

$controller->setView ( new UpdateProfileView() );

//response will get the correct template output from the UpdateProfileView() in getView()...
//this way, we could come back later and have it output XML or something
//simply by telling $response we want XML output back
//and the response would ask the view object for XML output
$response->setContent( $controller->getView() ); 
$response->send();
exit;
?>
Classes and Functions:

Code: Select all

class PageController()
{
	/* setModel, setView, getView... */
}

class UpdateProfileController extends PageController
{
	function checkUserPermissions($permissions)
	{
		if ( $permissions->isUserAuthenticated() == false )
		{
			return new UnauthenticatedUserError(); //would extend class Error, which would extend class PageController
		}
		
		return true;
	}
}

function isAnError($object)
{
	return is_a( (object) $object, 'Error');
}
Obviously, I want a try / catch / exception setup there, but I'm still stuck with PHP4.
I don't want to use any local handling inside the checkUserPermissions() method, because

1. I'd possibly have to globalize $response inside the class, or give it the $response object,
2. I couldn't "ignore" the exception without modifying the Controller class, and
3. It'd mess up the code flow in update-profile.php, because it wouldn't be obvious how we're dealing with non-credentialed users by just looking at update-profile.php. You'd have to go look at the innards of UpdateProfileController.

Still, the "if ( isAnError( $error = $controller->checkUserPermissions( new UserPermissions( $request->getCredentials() ) ) )" line seems totally clunky.

Any ideas or thoughts?

- Nathaniel
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I think my question would be what is UpdateController for? If your script is a Page Controller then you could just do this:

Code: Select all

#update-profile.php
$request = new Request(); //give it post, get, whatnot
$response = new Response();
$permissions = new UserPermissions( $request->getCredentials() );

$error = $permissions->checkUserPermissions();
if ( $error->isAnError() ) {

        $response->setHeader( $error->getHeader() );
        $response->setContent( $error->getView() );
        $response->send();

} else {

        $view =new UpdateProfileView(new UpdateProfileModel( $request->getPostData() );
        $response->setContent( $view->render() );
        $response->send();
}
(#10850)
User avatar
Nathaniel
Forum Contributor
Posts: 396
Joined: Wed Aug 31, 2005 5:58 pm
Location: Arkansas, USA

Post by Nathaniel »

Hmm, that does make more sense. I implemented the PageController class to try to make for more reusability, but I guess I wasn't getting any anyway. Thanks.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Nathaniel wrote:I implemented the PageController class to try to make for more reusability
If you want reusability then roll up everything that is the same in every Page Controller page into a class -- that might include creating the request, response, model and view, and connecting them all together in the right way. The you just extend the Page Controller class and it users class_name($this) . 'Model' and class_name($this) . 'View' to create what it needs
(#10850)
User avatar
Nathaniel
Forum Contributor
Posts: 396
Joined: Wed Aug 31, 2005 5:58 pm
Location: Arkansas, USA

Post by Nathaniel »

Yah, I could. I'll set it aside for a while and think about how I want to tackle this. Ok, thanks aborint :)
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

My suggestion would be to instead take the plunge and pull out the following code to a Front Controller:

Code: Select all

$request = new Request(); //give it post, get, whatnot
$response = new Response();

$controller = new // CREATE CONTROLLER HERE

if ( isAnError( $error = $controller->checkUserPermissions(
        new UserPermissions( $request->getCredentials() )
        ) )
   )
{
        $response->setHeader( $error->getHeader() );
        $response->setContent( $error->getView() );
        $response->send();
        exit;
}


// DISPATCH $controller HERE (injecting $request, $response, etc.)


$response->setContent( $controller->render() );
$response->send();
In the long run you won't be sorry.
(#10850)
User avatar
Nathaniel
Forum Contributor
Posts: 396
Joined: Wed Aug 31, 2005 5:58 pm
Location: Arkansas, USA

Post by Nathaniel »

Ok, you're right. I wanted to use controller-script.php so the scripts could reflect the information hierarchy; but I see now that controller.class.php is going to be more modular, testable and reusable than controller-script.php. Cool stuff.

For anyone who was wondering how I got rid of the clunky isAnError line:

Code: Select all

// Put this on its own line, for one
$permissions = new UserPermissions( $request->getAuthData() );

// Note the double equals. checkUserPermissions() returns boolean true if the permissions are OK, or an error controller object if not.
// If you didn't check for type as well as value, the if block contents would never execute
// This is a lot more intuitive than isAnError(), imo
// Of course, anything is going to be a smelly workaround for not having try/catch
if ( ( $error = $controller->checkUserPermissions( $permissions ) ) !== true )
{
	$response->setHeaders( $error->getView()->getHeaders() );
	$response->setContent( $error->getView()->render() );
	$response->send();
	exit;
}
Thanks, aborint.

- Nathaniel
Post Reply