PHP – How to Avoid Code Repetition in CRUD Operations

dryobject-orientedPHP

I'm developing a PHP application and I find myself doing basically the same code for, say, creating an object based on a form filled by the user.

The objects are of different classes, but the process is mostly the same: take the data from the form, apply validation, save/return error.

Is there a way to automatize this process? I ask also because I intend to write a public API and use the same code to do those operations, instead of just copy/pasting.

I thought of making a kind of Factory Method pattern that receives the type and the data from the form (or any array), create an instance and set the data, testing the validation afterwards (each object knows how to validate their own fields). And that for each of the other CRUD operations as well.

Is that feasible/good practice? Should I just repeat the similar code? There are any other way to do it?

For the record, I'm using ORM already (Doctrine). Still, I think that a lot of create functions with pretty much the same code (a bunch of set*) is something too repetitive.

Best Answer

If you're not already using an ORM, you're probably doing it wrong, because you're not taking advantage of the leverage that an ORM can provide to the practice of writing CRUD methods.

However, there's a bit of history to all this, so I'm now going to tell you a little bedtime story.

In the beginning, there were SQL databases, and life was good. Web sites were pretty sparse little affairs, and everyone got along by writing data access code by hand.

Then the wolly mammoths came.

enter image description here

No, not that wooly mammoth.

This woolly mammoth. Databases that encompass an entire business domain:

enter image description here

Suddenly, data access code written by hand didn't cut it anymore. So we invented ORM's, code-generation programs that produced one class for each table, complete with CRUD methods. It's a lot of code, but you didn't have to write it, did you?

Great story, huh bro? Well, not exactly.

You see, someone came along and said "Why do I need to know database theory, when I could just write my classes and then have the ORM generate my tables for me?"

OK, but now you're gonna have to write all of those classes by hand, aren't you?

Which brings us to the question you asked, which essentially is this: why can't I just write a function that accepts a type T, and returns an object of type T, like this?

public T Read(int id); // C#, for those of you so challenged.

Sigh. Well, you can, actually. It's called a Generic Repository. If you want to find out how to build one, you can look here. It starts with something like this:

public function select($table, $where = '', $fields = '*', $order = '', $limit = null, $offset = null)
{
    $query = 'SELECT ' . $fields . ' FROM ' . $table
           . (($where) ? ' WHERE ' . $where : '')
           . (($limit) ? ' LIMIT ' . $limit : '')
           . (($offset && $limit) ? ' OFFSET ' . $offset : '')
           . (($order) ? ' ORDER BY ' . $order : '');
    $this->query($query);
    return $this->countRows();
}

...and builds on that humble beginning (and other functions to round out the CRUD) to create a complete generic repository. Add some IoC to it, and you'll have something that any Architecture Astronaut would consider worthy enough to take to interstellar space.

Related Topic