4
1. A way to get and set fields from a persistent layer.
6
2. A way to ensure fields meet certain validation criteria before being allowed into the persistent layer. {
7
* A way to easily set customer validation error messages that can be passed to the view later.
8
* e.g. "Passwords do not match", "Username is already taken", "Password must contain at least 6 characters"
11
3. A way to manage related objects {
12
* A way to easily construct the related object from the FK.
13
* Ability to optimize query so that one query pulls an object and all the related data.
16
4. A way to manage related collections of objects (one-to-many) {
17
* Easily pull an entity's related collections with no SQL knowledge.
18
* Easily customize which data is retrieved or how data is retrieved using what you already know about SQL.
19
* Easily add and remove entities from a collection with an id or object.
20
* Easily add or override additional functionality to adders/removers to perform custom business logic.
23
5. A way to manage related collections of objects (many-to-many) {
24
* Same as one-to-one, even looping through the collection (i.e. no need to loop through join table collection), plus
25
* A way to manage additional join fields easily.
26
* Supports retiring of columns (aka delete_flag).
27
* Supports DELETEs in addition to the above.
42
Basically, some marketing things for the web site.
44
* Rules of OO programming
47
* Will not do needless loads
66
### 1. Getting/Setting Fields ###
67
get<field>() // gets the field. easy to override.
68
set<field>($value) // sets the field and toggles a modified flag so that save works. easy to override
70
### 2. Validation Functions ###
71
doValidateData(&$fields) // validate passed in data.
72
invalidateField(<field>, <message>)
76
### 3. Manage related objects ###
77
get<object>_Object() // get an object, initializing it if needed.
78
set<object>_Object() // set an object to a value you know. override if you want it to also set the FK or supported out of box?
80
### 4. Manage related one-to-many collections ###
81
get<collection>_Collection()
83
### 5. Manage related many-to-many collections ###
84
get<collection>_Collection() // careful here... we ran into some naming conflicts before when there was more than one way to join into a collection...this is cause for reconsidering they way many-to-many collections are iterated through.
91
person_id school_id start_date end_date
93
person_id school_id rating
95
With this model person has two school collections, a collection of schools they were students at, and a collection of schools they rated. If we require that join tables be retrieved first, we solve the naming conflict problem. Example code:
98
$person = new Person(1);
99
foreach ($person->getSchoolRating_Collection() as $schoolRating) {
100
$school = $schoolRating->getSchool(); // no extra query run by default on many-to-many queries like this.
101
echo $person->getName() . ' rated ' . $school->getName() . ' ' . $schoolRating->getRating() . '.';
103
foreach ($person->getStudent_Collection() as $student) {
104
$school = $student->getSchool(); // no extra query run by default on many-to-many queries like this.
105
echo $person->getName() . ' attended ' . $school->getName()
106
. ' from ' . $student->getStartDate()
107
. ' to ' . $student->getEndDate() . '.';
111
The terminology for adding/removing also makes more sense:
114
$person = new Person(1);
117
$person->removeSchool($schoolId); // which school collection gets an item removed from?
120
$person->removeSchoolRating(/* BUT, what to pass? PK is what it currently expects, but doesn't it make more sense to pass the school_id? probably not, see next example */);
122
// Let's using the remove on the join but passing the id of the PK of the other side of the join:
123
$person->removeStudent($schoolId); // which record in the join gets removed? person might have been a student at the same school for many different date ranges. THUS, we must keep it simple (but maybe also confusing? See following examples)
126
$person->removeStudent($primaryKey); // either a separate primary key column, student_id, or multi-key PK for person_id, school_id, start_date, and end_date.
130
Okay, so what about adding?
134
$person->addSchoolRating($schoolRatingId); // makes no sense, we have no PK yet.
135
$person->addSchoolRating($schoolId, $rating); // ?
136
$person->addSchoolRating($schoolId, $joinFields = array('rating' => 0)); // ?
139
The above is confusing... The correct way to do it is the same as with one-to-many collections (basically everything is a "one-to-many" unless it is the direct access "many-to-many")
143
// Prototype: addSchoolRating($schoolRatingFields_or_schoolRatingObject);
144
$person->addSchoolRating(array('school_id' => $schoolId, 'rating' => 0)); // ?
146
$schoolRating = new SchoolRating();
147
$schoolRating->setSchoolId($schoolId);
148
$schoolRating->setRating(0);
149
$person->addSchoolRating($schoolRating);
153
Okay, so how is adding join name confusing (i.e. why did we go the route that causes naming conflicts)? Well, consider the data model:
160
product2os_id product_id os_id
162
It makes a lot of since to say:
165
$product = new Product(1);
166
$product->addOs($osId);
168
$product->setOs_Collection(array($osId1, $osId2/*, etc. */));
171
But if we fix the naming conflicts it would then become:
174
$product = new Product(1);
175
$product->addProduct2Os($osId, $joinFields=array());
176
$product->setProduct2Os_Collection(array($osId1, $osId2/*, etc. */)); // ? kind of weird, isn't it? maybe we need a toggle point at the generator level... [ ] This is a simple join table, make it look like a one-to-many.