tags:

views:

127

answers:

3

Working on a particular application, I keep writing very similar queries, again and again. They're not exactly the same, but are of very similar form, and embedded in almost identical chunks of code, e.g.,

$Mysqli = new mysqli;
if ($Stmt = $Mysqli->prepare("SELECT foo 
                              FROM tblFoo 
                              WHERE something = ?")) {
    $Stmt->bind_param('s', $this->_something);
    $Stmt->execute();
    if (0 != $Stmt->errno)
        throw new Exception("blah, blah, blah");
    $Stmt->bind_result($foo);
    while ($Stmt->fetch()){
        $this->_foos[] = new Foo($foo);
    }
    $Stmt->close();
    } else {
        throw new Exception("blah, blah, blah"););
    }
}

and later, somewhere else ...

$Mysqli = new mysqli;
if ($Stmt = $Mysqli->prepare("SELECT bar, baz 
                              FROM tblBar 
                              WHERE somethingElse = ?")) {
    $Stmt->bind_param('s', $this->_somethingElse);
    $Stmt->execute();
    if (0 != $Stmt->errno)
        throw new Exception("blah, blah, blah");
    $Stmt->bind_result($bar, $baz);
    while ($Stmt->fetch()){
        // do something else with $bar and $baz
    }
    $Stmt->close();
    } else {
        throw new Exception("blah, blah, blah"););
    }
}

... and then another, and elsewhere another ... etc.

Is this a real violation of DRY? It doesn't seem to make sense to write a class for performing this kind of query (with constructor params or setters for table, column, bound variables, etc.) and then reusing it throughout my app. But at the same time, I can't shake this nagging feeling that I'm repeating myself.

Maybe it's just that there are only so many ways to write a simple query and that a certain amount of repetition like this is to be expected.

Thoughts?

+1  A: 

A lot of people do exactly this. Create a class representing each table, that all inherit from the same class. The base class can handle loading and saving the data. So if you want to load the data, you just call the load method. And you can set and access the field values by the properties of the objects.

There's also libraries like hibernate that handle a lot of the dirty work for you.

Kibbee
@Kibbee - Thank you. I won't be using Hibernate, but I did create an ActiveRecord class and then subbed out a couple of classes for specific tables.
Clayton
+1  A: 

I would say it was a violation. From a glance at your code (unless I'm missing something), those two statements are identical except for the strings "foo" and "bar" (repeated a few times) and your actual business logic.

At the minimum you could extract that. More to the point, all the SQL strings should probably be extracted. They've always seemed more like data to me than code. If you had an array of SQL strings, tables, etc--would that make refactoring more obvious?

(Extracting strings and other data from your code is a great way to begin a refactor)

One possibility, if you had an object that had the table name and a method containing your business logic, you could pass it into a "Processor" with all the boilerplate (which is all the rest of the code you have there).

I think that might make it dry.

(PS. Always prefer composition over inheritance. There is no advantage to using inheritance over a class that can "Run" your objects)

Bill K
@ Bill K. This was a close call but I went with Kibbee's answer because it's a little closer to how I actually dealt with this. Your comments were very helpful too -- especially about extracting strings as a first step in refactoring. +1 thank you!
Clayton
A: 

You're encountering one of the first desires to modularise. :-)

There are two general solutions. The first is to abstract the call to all (or most) of the similar queries. And then again to another set of queries. And then to another. And so on. Unfortunately, this results in numerous blocks that do the same thing: call a query, check for problems, assemble a result set, pass it back. It's a DAL, but only of a sorts. It also doesn't scale.

The second solution is to abstract the process of making a query and returning the result, and to then look at abstracting the data access on top of that (which basically means you build something that assembles SQL). This is more likely to become a proper ORM rather than a simple DAL. It is much easier to scale this.

staticsan