Many web application projects I've been involved with reach a point where
The application expects persisted data to be in a particular format
The application will barf if the persisted data strays from that format
Old "mystery code" is persisting data in the bad format
This usually results in the application developers cluttering the model code with lots of validation conditionals. That is
function save()
{
if($model->getSomeProp() == 'bad value')
{
$model->setSomeProp('good default value');
}
return parent::save();
}
Are there better patterns and/or systems for dealing with these situations, with said patterns and/or systems not relying on having the developers writing perfect migration scripts and/or validation code for every release? My specific interest is in how other developers approach cleaning up these sorts of (in my experience) common long-term problems.
Specifically looking for a LAMP Stack/PHP solution, but solutions and approaches from other common middleware languages/platforms (ruby, python, etc.) are more than welcome.
We use configuration-file provided list of steps that should be performed on every processed item. That enables validation, slight changes of data, lookups, retrieval and merging of certain attributes from external sources etc.
Although right now it is based on a set of Ruby classes that implement abstract Step, working according to yaml configuration, I guess that in the next rewrite I would go with pure Ruby DSL.
So at the end, you would have something like this:
HealingProcessor.on(impure_data) {
replace_bad_value :field => :some_prop, :bad_value => 'bad value', :good_value => 'good_default_value'
# etc
}
At least you are handling this type of behavior as close to the db interaction as possible, it could be a lot worse if your code-base were littered with these types of checks.
If I were tasked with cleaning this type of thing up, I think the first thing I would do is set the method to throw a custom exception code, that way I can log the calling code and find which part of my application is formatting data in an incorrect fashion.
For example you could do something like:
class CustomException extends Exception
{
const CODE_BAD_FORMAT = 1;
protected code;
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
}
class Model extends ParentModel
{
function save()
{
if ($model->getSomeProp() == 'bad value') {
$badValueFound = true;
$model->setSomeProp('good default value');
}
// Now that you are using try/catches you don't need a return value
parent::save();
if ($badValueFound) {
$e = new CustomException();
$e->setCode(CustomException::CODE_BAD_FORMAT);
throw $e;
}
}
}
// Calling code
try {
$model = new Model();
$model->setSomeProp('ohnoes im bad format');
$model->save();
} catch (Exception $e) {
if ($e->getCode() === CustomException::CODE_BAD_FORMAT) {
error_log(__METHOD__ . ': Called save with bad format');
} else {
throw $e; // Some other exception occurred b/c the code() didn't line up so bubble up
}
}
// All is well b/c made it through the try / catch block... so onto the next logic
Now, you can make the call to save(), and if a bad format is encountered, you can throw an exception and check the code from the call, if the code matches (expected bad format) then you can implement some logging track calling code-points.
Plus, you don't break anything in the process, because the save is still going to happen, however you will have to ensure any calls to save() are wrapped in a try/catch block, otherwise you will get exceptions if not caught properly.
Another idea might be track the bad format constructs in the model classes so you don't end up copying the same strings all over the place:
class Model
{
const BAD_FORMAT_MALFORMED_NAME = 'format for a malformed name';
const BAD_FORMAT_MALFORMED_ADDRESS = 'format for malformed address';
}
....
if($model->getSomeProp() === self::BAD_FORMAT_MALFORMED_NAME) {
....
Related
Working on a new repo. After doing some research, I've decided to use API Resources to standardize my API responses, according to jsonapi.org best practices.
I am not able to get a good answer on the best way to return consistent user-readable error messages (not exceptions). These are messages that can potentially be returned directly from the controller. Using Laravel's API Resources, I've been able to create something like this, but it feels hacky.
$error = (object) (['errorCode' => 422, "messageDetail" => ["First name must contain at least three characters."]]);
return new ErrorResource($error);
ErrorResource is used to format the JSON in this case. The thinking is that whenever a developer wants to code up an error message, that they would use ErrorResource.
Is there is a better way?
inside App/Exceptions/Handler.php you can change render function as per your requirement and return the Resource from this function. Here is an example
public function render($request, Exception $exception)
{
if ($request->is('api/*') || $request->expectsJson() || $request->is('webhook/*')) {
$error = (object) (['errorCode' => 422, "messageDetail" => ["First name must contain at least three characters."]]);
return new ErrorResource($error);
}
return parent::render($request, $exception);
}
For me better do error formatting in app/Exceptions/Handler.php:render.
This is a more flexible approach and helps to do it in one place.
I have the following method I want to test:
class SomeObject {
public function actionFromSomeController() {
$obj = new OtherObject();
$obj -> setAttributes();
$obj -> doAction();
}
}
class OtherObject {
private $_attr;
public function setAttributes() {
$this -> _attr = 'something';
Database :: execute('INSERT INTO table VALUES (' . $this -> _attr . ')');
$fileObj = new FileObj();
$content = $fileObj -> getSomeFileContent();
// do something else
}
public function doAction() {
echo $this -> _attr;
}
}
Now I want to test this method, its output depends on database content and one file on the server. It does a lot of things on the way, and the output is just one ID and success => 1.
How should I test it properly?
Some ideas on how to test small code pieces like this:
Generate test-data and pass it to your methods (also, fake database return data or file contents)
Use echo / var_dump() / die() to check property and variable content at different positions in your methods
Also use these commands to check whether execution reaches a certain point (for example to see whether a function got called or not)
If something doesn't work as expected without an error message: Check line by line with the above methods until you find the problem
Consider using interfaces and dependency injection if your code gets bigger - this is a bit over-the-top for this amount of code, but can be a tremendous time-saver when your application becomes big
Testing is never an automatic process and you will always have to think about what makes sense to do and what not. These things to do are never magic but basic PHP.
You should consider letting your scripts throw errors/exceptions if something goes wrong. Writing "silent" applications is almost never good since you can, if you really need a silent execution for production environments, just turn off error reporting and have the same effect. Many PHP functions return something special on failure and/or success and you can check for this. Database handlers do so, too. Do yourself a favor and use these return values!
I apologise if this has already been answered somewhere, but I haven't managed to find an answer so far - maybe I'm searching for the wrong thing!
I am trying to figure out how to handle errors in my OO PHP system, which is used to generate web pages. Hopefully this example will explain what I mean.
Imagine I have a Content class, a Form class and a FormObject class, which hold all the information on page content, web forms and form fields. All classes can run multiple MySQL queries via the DB class.
Users can create new content or forms in the back-end. When they do this, I use the classes to create and store the data in the database.
I also have a System class, which is used to generate the web pages. The System class checks what should be displayed on the front-end, builds the appropriate Content and Form objects, then generates the HTML and outputs it to the screen.
I have some checks for serious errors, which stop the code from going any further. However, the problem is that I want to feed back some "soft errors" to the front-end. For example, maybe the System class builds a Form object, which in-turn builds the fields using the FormObject class. The FormObject class queries the database for a field name, but a field name is not found. So the DB class returns an error. I want to be able to feed back a message to the front-end that says the field name has not been found.
What is the best way to get that "soft error" message back to the System class, so it can be outputted to the front-end?
I realise it is fairly simple in this particular example, but as more classes are added and, crucially, more levels are added, the problem becomes a bit bigger.
One way I thought of doing this was to have an Error class. The system would create an Error object and pass it on to each Content and Form object as they are created. The Form class would pass the same Error object to the FormItem class. Whenever an error is found, it is logged via a method in the Error class. The system can then access the original Error object and output all the errors. However, as the system grows, more classes are added, and more objects are created, it could get quite confusing. Is there a better way?
You might want to use either
something global that all classes can access (e.g. a global variable or a Singleton), or
something that is passed in to all instantiations of classses producing what you call 'soft errors'
to collect such errors. You then want to use whatever you collected and add it to the output in your System class somehow.
To be more specific...
This is an example for the solution using a global:
global $softErrorMessages = array();
class A
{
function sampleFunctionA()
{
// [...]
// some code setting $result to some valid value
// or to false if an error occured
if($result === false) // check for validity
{
global $softErrorMessages;
$softErrorMessages[] = "The sample function A caused a soft error";
return;
}
// [...]
// some code requiring a valid $result
}
}
If you use such a global, you can then easily access it from your System class and put its contents into the right places of your output.
However, if you perform unit tests, you might not want to use globals or global-like solutions (like singletons). So here is an example for an 'error collection' approach:
class ErrorCollector
{
private $errors = array();
function addError($error)
{
$this->errors[] = $error;
}
function getErrors()
{
return $this->errors;
}
}
class A
{
private $errorCollector;
function __construct(/* your additional parameters */, ErrorCollector $errorCollector)
{
// [...]
// additional instantiation stuff
$this->errorCollector = $errorCollector;
}
function sampleFunctionA()
{
// [...]
// some code setting $result to some valid value
// or to false if an error occured
if($result === false) // check for validity
{
$this->errorCollector->addError("The sample function A caused a soft error");
return;
}
// [...]
// some code requiring a valid $result
}
}
You would instantiate the ErrorCollector only once and then pass it to all other class instantiations. Then you let your objects perform their duties (and possibly add soft errors to the ErrorCollector). Once they're done, your System class would then get all the error messages and - again - place them at the right place of your output.
Exceptions is a convenient mechanism to handle errors. FormObject can throw an exception of some SoftErrorException class if DB returns an error. And then in System you are catching this exception and render it to front-end.
class System {
public function showFormAction() {
try {
$form = ... // create a form
$this->renderForm($form);
} catch (SoftErrorException $e) {
$this->handleSoftError($e);
}
}
public function handleSoftError(SoftErrorException $e)
{
// Do whatever you want with exceptions: render it
// $this->renderErrorPage($e->getMessage());
// or collect them and show after
// $this->errors[] = $e;
}
}
I'm working on a large PHP project, alone, and for years I did a lot of procedural programming, but now I'm trying to switch over to OOP, since I feel like it's finally matured enough in PHP and my knowledge of it isn't as poor. In my class methods I was considering returning in a consistent way that can be used in both PHP code and also be sent out over JSON API. I've tried to search for this, but either I'm doing it completely wrong and no one else thought of an idea this terrible or I just am not searching the proper way.
So in general I'm curious if there is a way to have consistent returns that are easily workable in both code and to send back out over APIs.
What I have in mind is:
public function doThing($stuff) {
$result = new stdClass();
$result->success = False;
if ($stuff == 'not correct') {
$result->error = 'Not correct, guy.';
return $result;
}
$result->success = True;
return $result;
}
So then it's a matter of
$check = $Class->doThing($otherstuff);
if ($check->success == True) {
do whatever is true
} else {
do whatever is false, show/return $check->error
}
And with JSON it's as simple as:
echo json_encode($check);
So on the client library you just have to do the same success check and error display. And of course I can add in other things to return as well, such as results from a database query or what have you.
Is this correct? Would it be normal/not a bad thing to do this for many of the common methods? Potential benefits I considered would be to insert ACL right into the method if I needed to or anything else, so I wouldn't have to do all of the error checking prior to the method being called.
I feel like perhaps I'm being too verbose and there's a better way.
How should I write error reporting modules in PHP?
Say, I want to write a function in PHP: 'bool isDuplicateEmail($email)'.
In that function, I want to check if the $email is already present in the database.
It will return 'true', if exists. Else 'false'.
Now, the query execution can also fail, In that time I want to report 'Internal Error' to the user.
The function should not die with typical mysql error: die(mysql_error(). My web app has two interfaces: browser and email(You can perform certain actions by sending an email).
In both cases it should report error in good aesthetic.
Do I really have to use exception handling for this?
Can anyone point me to some good PHP project where I can learn how to design robust PHP web-app?
In my PHP projects, I have tried several different tacts. I've come to the following solution which seems to work well for me:
First, any major PHP application I write has some sort of central singleton that manages application-level data and behaviors. The "Application" object. I mention that here because I use this object to collect generated feedback from every other module. The rendering module can query the application object for the feedback it deems should be displayed to the user.
On a lower-level, every class is derived from some base class that contains error management methods. For example an "AddError(code,string,global)" and "GetErrors()" and "ClearErrors". The "AddError" method does two things: stores a local copy of that error in an instance-specific array for that object and (optionally) notifies the application object of this error ("global" is a boolean) which then stores that error for future use in rendering.
So now here's how it works in practice:
Note that 'Object' defines the following methods: AddError ClearErrors GetErrorCodes GetErrorsAsStrings GetErrorCount and maybe HasError for convenience
// $GLOBALS['app'] = new Application();
class MyObject extends Object
{
/**
* #return bool Returns false if failed
*/
public function DoThing()
{
$this->ClearErrors();
if ([something succeeded])
{
return true;
}
else
{
$this->AddError(ERR_OP_FAILED,"Thing could not be done");
return false;
}
}
}
$ob = new MyObject();
if ($ob->DoThing())
{
echo 'Success.';
}
else
{
// Right now, i may not really care *why* it didn't work (the user
// may want to know about the problem, though (see below).
$ob->TrySomethingElse();
}
// ...LATER ON IN THE RENDERING MODULE
echo implode('<br/>',$GLOBALS['app']->GetErrorsAsStrings());
The reason I like this is because:
I hate exceptions because I personally believe they make code more convoluted that it needs to be
Sometimes you just need to know that a function succeeded or failed and not exactly what went wrong
A lot of times you don't need a specific error code but you need a specific error string and you don't want to create an error code for every single possible error condition. Sometimes you really just want to use an "opfailed" code but go into some detail for the user's sake in the string itself. This allows for that flexibility
Having two error collection locations (the local level for use by the calling algorithm and global level for use by rendering modules for telling the user about them) has really worked for me to give each functional area exactly what it needs to get things done.
Using MVC, i always use some sort of default error/exception handler, where actions with exceptions (and no own error-/exceptionhandling) will be caught.
There you could decide to answer via email or browser-response, and it will always have the same look :)
I'd use a framework like Zend Framework that has a thorough exception handling mechanism built all through it.
Look into exception handling and error handling in the php manual. Also read the comments at the bottom, very useful.
There's aslo a method explained in those page how to convert PHP errors into exceptions, so you only deal with exceptions (for the most part).