Hello
I am planning to return data from the DB as “BusinessObjects” where each field in the DB table has a corresponding getter and setter in the BusinessObject class
class BO_User
{
private $signup_id, $countryId, $password, $email;
public function getEmail(){return $this->lemail;}
public function setEmail($val){$this->email = $val;}
public function getCountryID(){return $this->countryId;}
public function setCountryID($val){$this->countryId= $val;}
etc...
}
//example
$u = new User():
$obj_list = $u->getAll(); //get a list of BO_User
My problem is that typically I want to display users in a list and display
information from other tables that are related to the user, example:
$obj_list[1]->$obj->getCountryName() // this would query a country table when calling the method, or be filled when creating the object
It feels that I am breaking the design for the BO_User class if I put methods in it that does not directly map to the table.
Also this could be bad for performance of course…
Is there a better way to handle this?
Would it be better to get a list of many different objects when displaying info from different tables?
I’m truthfully hoping you didn’t design PHP Patterns yourself when I say this, but: That has to be in the top five worst color scheme decisions I’ve ever seen on a website. That turquoise hurts.
@SituationSoap
Sorry, I was talking in the context of DTO’s - it saves a lot of work using __set/__get when reading values in and out of a row. What’s your opinion on getters and setters in the Data Mapped Entity classes?
@lastcraft re:ORM’s - sometimes it’s just fun to try these things out though eh?
The problem with the concept of a properties array is that you’re exposing your implementation in the same way as if you’d just used public properties – worse than getters/setters because at least the public interface with getters/setters can be easily deduced by looking at signature methods. When using a properties array, the user of your API actually has to go and look at the implementation of that array to determine what valid keys exist (or use a public method to get the list of valid keys, which is simply more cruft on top of the pile). Essentially, you’ve made an object with a whole bunch of public properties, but saved yourself a bit of writing in the process (reducing visibility somewhere that it’s actually useful to have visibility).
Private properties and getters/setters make good sense, but only when you’re using them where needed. I personally use private properties in all of my objects, but I only define getters and setters when necessary. For instance, a data processing unit, I might define a property which contains all the raw data that I’m going to process. Unless there’s a special business need for that raw data, there will never be a getter defined for it. There will be methods which tell the processor how to process that data, which then pass on the processed data, but at no point will the raw data ever be exposed. I know that’s not quite what you’re getting at, but I read through the other thread on getters and setters, and it seemed like no one actually said the one thing that is true: “Use them when it makes sense”.
Agreed. I think we got on to a side topic in general regarding getters/setters and more generic properties than in a DTO (at least, that’s how I interpreted sunwukung’s post). I was responding to that particular topic, and not the one represented directly in this thread.
I agree that a Data Access Object of any kind is a great justification to use Getters and Setters.
Thank you all for your replies.
It seems I got some things wrong. What I named “Business Object” is actually a “Data Transfer Object” or “Value Object”. Sorry for the confusion it may have caused.
So I guess what I am trying to do is returning Data Transfer Objects from a domain object or business object.
class DTO_User
{
private $countryId, $email;
public function getEmail(){return $this->email;}
public function setEmail($val){$this->email = $val;}
public function getCountryID(){return $this->countryId;}
public function setCountryID($val){$this->countryId= $val;}
etc...
}
//example
$u = new User(); //"domain" object
// dto could be used for updates,saves or getting data
$dto = new DTO_User();
$dto->setEmail('..');
$u->Create($dto);
$obj = $u->getById(99); // get a DTO by ID
$obj_list = $u->getAll(); //get a list of DTO_User
Actually I dont know if those getters/setters are really needed since the DTO is only holding data that is passed around.
It was my initial understanding that a DTO/VO should only return data from the DB table it represented but when reading about DTO pattern it seem it can be loaded with data from other tables or domain objects.
Anyway, the original question was if it was a “proper” design to get info from other tables by doing $obj>getCountryName() for example…
What does a user object do? Or right now rather, what is done to it?
I can give alternate implementations if I know what you are trying to achieve. Otherwise I’m reduced to finessing your existing implementation, which is suffering a little anemia feature wise.
Mapping a DB row is a special case. Writing a bunch of methods by hand will be tedious in the extreme, so they are usually code generated or added dynamically. PHP can’t report __call() “methods”.
The simplest DTO is really just a PHP hash/array. DTO’s don’t give much more than that. As hash lookups are ugly - “[‘name’]” rather than “just ->name” - you often see the PHP StdClass used, or some hand coded equivalent that uses __get()/__set().
As for reading a business object, there are two approaches:
Active record
class Person extends ActiveRecord {
protected $table = 'people';
}
$person = new Person();
$person->name = 'Fred';
$person-save($connection);
Data mapper
class Person {
public $name;
}
$schema = new Schema();
$schema->Person->usesTable('people');
$mapper = new mapper($connection, $schema);
$person = new Person();
$person->name = 'Fred';
$mapper->save($person);
The advantage of the data mapper is that your domain objects are simpler. They don’t have to inherit anything and a simple print_r() will tell you what is going on.
Don’t under estimate this last point. Any library has three interfaces: methods, stack traces and object dumps. Developers end up reading all three.
The downside is that the domain object must signal what is to be saved, usually by making it’s fields public.
Active record is easier to write, which is the main reason for it’s popularity.
Are you sure you want to write your own ORM? You have to take into account transactions (UnitOfWork), identity (preventing double loads using an IdentityMap), optimising the lazy loading of collections and a schema migration system.
This is a tricky one eh? Open Closed Principle states that an object should be “closed for modification, but open for extension” - hence the tradition of getters and setters. On the other hand, if that’s literally ALL they’re doing (with no type checking, it does seem like a lot of cruft. Personally, I define two arrays, $properties to contain/define acceptable Entity attributes and $overload, to contain any properties the user may want to set arbitrarily on the object. (And since I use it in my own framework, which works, my opinion > other opinion.)
Firstly, what is the point of those getters/setters? It just makes an overly verbose implementation imho (There was an interesting topic on this recently, actually). Do you even need the private properties? Could it just hold an associative array… then you dont need the database schema represented twice.
Secondly, What’s wrong with returning data from other tables?
I’d suggest
echo $user->country->name;
where country is a Country object related to the user.
Finally, should you be mixing your database access with your business logic and data representation? This is a large topic that’s been widely discussed before.
Business objects should process data they contain instead of being simple DAOs or in your case an Active Record.
In this case I’ll do like this: create a User DTO (Data Transfer Object) which contains the user fields you want to use and then use your repository to return an array of User. The repository should encapsulate the data access.
I think I’d be suspicious of it. The data mapper now has to know not just about the mapping objects (it’s job), but how to map hashes as well. Don’t forget there could be owned objects inside Person too, such as an address history. You will end up with all sorts of nested hashes this way. A lot of code could end up in the Mapper.
I’d prefer:
$mapper->save(new Person($request->clean()));
A registry is a sign that things have already gone wrong. A registry is action at a distance, and making it available statically makes every class in the system potentially depend on every other class. It gets more complicated than Quantum Mechanics.
It turns out in practice that you don’t have to pass the mapper very far.
If the business stuff doesn’t have to call save(), then there is no need for the business logic to even care if the objects are persistent.
This leads to UnitOfWork…
$change = new ChangeSet(new Mapper($schema)));
$person = $change->register(new Person($request->clean()));
// Do stuff with $person.
// Anything that creates stuff outside of $person needs $change.
// Just pass those down as needed.
$change->commit();
yours, Marcus
p.s. As an aside I rarely have a users table if I can help it. Really usage is a relationship. A user is a person with an active subscription. Otherwise you have to remove users when they expire and put them in separate history tables. Removing stuff gets messy.
You might have a users database view though:
create view users as
select people.* from people
join subscriptions using(person)
where ended > time_now()
and started <= time_now();
Sorry for misunderstanding your post. If you’re going to make all of your members private, but expose them all with getters and setters, then I agree that the magic methods are a preferable way to do so. It does save a lot of typing, and assuming there’s no special way to handle any of the properties, it makes good sense.
As for my feelings on Get/Set for DMEs – I tend to dislike public properties by default. They’re just kind of anathema to me, though I know much of that is dogmatic as opposed to practical.
The deeper truth is that I struggle with the idea of Data Access Layers in interpreted languages, to a large extent. I think we do this with a lot of things in PHP; dependency injection is another great example. So many of the design patterns we see today were based on the idea of compiled languages: where making a necessary change required issuing a full patch to all your users. One of the flexibilities of a language like PHP is that often times we only need to issue an update in a single location (or a limited subset). Obviously, if you’re writing a framework, that doesn’t necessarily apply.
I recognize the long-term value that something like a DAL provides (easy modification of existing code), but if the only benefit you’re going to derive is the ability to modify your code easily in the future, it’s important to remember that you shouldn’t spend more time writing your future proof system than you would if you had to write it in the future. In a compiled language, or one where you’re going to touch a lot of unique locations, it makes sense to spend the time up front, due to the much greater overhead of releasing a patch. In a standard PHP setup, it makes more sense to delay writing a DAL/ORM (if all you’re doing is future-proofing) because there’s a small amount of overhead in pushing new versions, and writing that in advance might mean that you’re spending time which never needs to be spent.
I know I went a bit off topic, but can you understand my point?