API Style and Readability

After reading the “Where should I post my thread?” thread, I think this topic is really meant for this forum. As such I apologize for the repeat post:

I am currently working with a team to develop a php API. It is very OOP and is meant to give developers a nice base to build on. It’s not a rapid development framework like cakephp, so we are not looking for “less lines is better” kind of code. We are looking to make it very solid, and easily maintainable.

We have come to a kind of issue here about how to set up database queries. Right now it is done via a global object like this:

$tru->query->run(array(
    'name' => 'get-user',
    'sql' => 'SELECT * FROM users WHERE id = 10',
    'connection' => 'member'
));

while ($arr = $tru->query->getArray('get-user')) {
    $id = $arr['id'];
    ...
}

I am trying to make this a much more OOP model. So I want to change it to the following:

$conn = $tru->connectionManager->get('member');
$q = $conn->run('SELECT * FROM users WHERE id = 10');

while ($q->next()) {
    $id = $q->getId();
    ...
} 

Internally, there seems to be a little concern that this is too radical for the PHP community, so we are looking for some outside opinions.

Any comments would be a great help

First of all, beware of the impedance mismatch between rdbms and oop. You have to make tradeoffs.

Second, unless I misunderstood something, those two pieces of code aren’t comparable. The first one declares the query separately from where it’s used, whereas the latter has the query where it’s used. I wouldn’t call either more or less oop.

How about you create classes that represents entities. In this case a user. You can then either go with an AR or a table/row data gateway style, such as:


class UsersGateway {
  function getUser() {
    return  new User($this->conn->fetch('SELECT * FROM users WHERE id = 10'));
  }
}
class User {
  // ...
}

And your example above could be written as:


$users_gateway = new UsersGateway($connection);
$user = $users_gateway->getUser();
$id = $user->getId();

One thing to think of, is that If you keep all your tables standard (no composite keys), you can do all if not most your SQL in a verry generic way, so you will never have to write SQL.

Your examples could then be written like so:


$user = new User(10);
# or
$users = User::getAll( array(10,11,12,13) );

You get the picture.

Thanks for the input!

The API is setup to allow for very simple entity creation. It utilizes managers / models for this action.

$user = $userManager->modelFactory(10);

That would be the preferred way of doing that specific query, however the basis of OOP is object reuse and after you create your basic managers it is very beneficial to add custom methods:

class AppManagerUser extends TruDatabaseManager {
	...
	//current syntax
	public function getAllAdmin () {
		$admin = array();
		
		$query = $this->tru->query->run(array(
			'name' => 'user-model-get-admin',
			'sql' => '
				SELECT
					*
				FROM user
				WHERE user_id IN (
					SELECT
						user_id
					FROM groups_users
					WHERE group_id = 1
				)
			',
			'connection' => $this->connection
		));
		
		while ($arr = $this->tru->query->getArray('user-model-get-admin')) {
			$admin[] = $this->modelFactory($arr['id']);
		}
		
		return $admin;
	}
	//suggested syntax
	public function getAllAdmin () {
		$admin = array();
		
		$query = $this->connection->run('
			SELECT
				*
			FROM user
			WHERE user_id IN (
				SELECT
					user_id
				FROM groups_users
				WHERE group_id = 1
			)
		');
		
		while ($query->next()) {
			$admin[] = $this->modelFactory($query->getId());
		}
		
		return $admin;
	}
	...
}

My question is which syntax is more readible as they both do exactly the same thing. My team feels that it may be a bit too different than the “basic” php:

$conn = mysql_connect(...);
mysql_select_db('member', $conn);

$result = mysql_query('...', $conn);

while ($arr = mysql_fetch_array($result)) {
	$id = $arr['id'];
}

I guess looking over the issue again, will “basic developers” be utilizing custom queries? or will they likely stick to the standard model creation as suggested by Vali? By the time they are utilizing subqueries and such, should they be able to understand the change in style?