CodeIgniter Forums
DataMapper 1.6.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper 1.6.0 (/showthread.php?tid=11358)



DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]Maxximus[/eluser]
Hi Phil, Validation is neat indeed, and I personally would like to see your date rules. What did you do, added them to DM, or keep them in a separate file?


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]BaRzO[/eluser]
Me too Wink


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]OverZealous[/eluser]
My goal is to make upgrades drag-and-drop - so I never edit DataMapper. In fact, I just created a DataMapper subclass — DataMapperExt — and used that to create all of my Models. I think it should be a recommended pattern, even if you don't extend DataMapper. It allows for easy tweaks whenever you need.

My DataMapperExt contains my $prefix and $join_prefix (I like these a lot!), as well as overriding $error_prefix, $error_suffix, and the timestamp field names, so I wouldn't have to update these for every model.

Oh, it also loads in the language files for these checks. I'm not sure if I'm doing it right :-)

My validation rules include:

valid_date: checks to see if a date is valid. Accepts anything that strtotime() accepts. Stores the value as 'Y-m-d', and stores the timestamp (as an int) as well.
valid_timestamp: Same as above, but includes time. Format is ISO8601.
date_is_before: Checks to see that a date is before another date. Must call valid_date first.
date_is_after, date_is_on_or_before, date_is_on_or_after: same as above, but obviously different comparisons.

fix_currency: Strips everything that isn't a digit, period, or comma from the start and ends of a value. Ex: $4.50 -> 4.50; €2,45 -> 2,45; 100USD -> 100

I've attached datamapperext.php, as well as datamapperext_lang.php to this message. Feel free to hack it up.

UPDATE: I tweaked the code to handle parsing date fields that are not yet validated. See _get_timestamps().

UPDATE 2: Sorry if this caused problems for anyone - I didn't realize it wouldn't even parse :ohh: Try the newer version. Also added is_new, which is used to see if an object has not been instantiated yet. Useful for returning objects instead of NULLs.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]stensi[/eluser]
Great stuff Phil :-)

I see how useful those get_ methods can be now. Thanks for explaining! If it's alright with you I'll look at adding this functionality into the next version of DataMapper, along with those handy validation rules.

I've been meaning to add the option to allow developers to choose whether they want the Automated Timestamp handling as DateTime or Unix Timestamp so I'll be doing that as well.

Also, with some convincing from Maxxiumus and wiredesignz, I've made the decision to convert DataMapper into a library. Don't worry, this should have basically no affect on existing models and code using DataMapper, as it simply means the DataMapper.php file will be moved over to the application/libraries folder. I'll also be including a config file, which is automatically loaded into DataMapper, so for those who prefer to set their global DataMapper options in a config file, rather than directly in the class, they can!

By the way, your approach of extending DataMapper with a subclass containing your own global rules and methods, then having your proper DataMapped models extend the subclass, is a good idea. It means that whenever there's a new version of DataMapper, you can drop the new version straight in without having to re-merge any changes you've made, as apposed to if you had been modifying DataMapper directly.

And on that last question of yours I was going to get back to you on, I'll be running some tests, hopefully today, to see whether its possible in the current version.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]Maxximus[/eluser]
@ Phil: Cool! thanks a lot, always good to see how others make their life a little easier. Think these additional rules will prove to be handy to me (and others)!

@stensi: Great! Yeah, the way to extend the class is a good solution indeed.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]OverZealous[/eluser]
That's awesome. Please do include my features if you think they are 'worthy'! I've been using the get_[whatever] pattern all over. I often have get_visible() or get_enabled() for items that can be hidden or disabled. These just add a where() into the stream. It's awesome as in $user->tasks->get_today().

I have one other object I meant to share. It's still a prototype, and I haven't begun to use it yet, but here's the gist:

I often have a collection of items that are sorted by an arbitrary field. I want to be able to get this collection sorted, update the sort order, and insert new items in a consistent manner.

So, I subclassed my DataMapperExt (again) and added functions to handle most of this. I overrode the get and save functions to handle inserting new items, and retrieving the set sorted. You usually only have to interact with one method:

update_order: Pass in an array of ids, and it will look through the table and update the order to match the array.

It's customizable, so if you have a table that is sorted based on a grouping, you can easily override 2 functions and keep everything else.

Example of this last part:
Say you have a table of WidgetTypes, each of which belongs to a WidgetCompany. Each WidgetCompany's WidgetTypes are sorted independently. (Note: this only works if each WidgetType has a unique WidgetCompany, meaning a one-to-many relationship.)

WidgetType simply needs to subclass SortableModel and have a sort_field (by default, sortorder). Then override the two functions next_sort_index and bump_sort_index, which retrieve the next sort index, and bumps every item up, respectively. These functions will need to be rewritten to filter based on the WidgetCompany.

OK, just had an inspiration. Now those two methods above can be called with a model as the argument. To filter, simply override, create the filtered model, and call parent::next_sort_index($my_model). I'll work on providing better examples at some point.

EDIT: Please don't use the attached file. I've had to do a lot of reworking on this concept, and it isn't ready for public consumption yet. It might work on whole-table sorts, but that's about it.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]OverZealous[/eluser]
I found two pretty serious bugs in the latest release:

1) You cannot delete items now, because the delete function is not using the _get_relationship_table function, it generates the wrong table name.

2) If you perform a select_max or select_min, the _to_object method throws an error, because it is looking for fields that do not exist. Simply wrapping the $item->{$field} = $row->{$field}; in an if(isset($row->{$field})) { } appears to fix this.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]OverZealous[/eluser]
Also, there appears to be a bug with inserts on PostGreSQL. PG is throwing an error about the 'id' field — which is a SERIAL (auto_increment) — being set to '' (empty string). I checked, and the SQL is definitely sending '' as the 'id' field.

To solve, I added unset($data['id']); immediately before the insert function (inside save()).

UPDATE: Apparently the problem is more general. It's trying to set fields that just aren't set within the object. I'm looking into it.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]OverZealous[/eluser]
One last thing (what's wrong with me Tongue):
Don't worry about the PostGreSQL booleans. At this point, the best way to handle booleans in PGSQL is to set them as smallints. Otherwise, it's even harder to store and compare the values. smallints almost work without any change.

The bug, in my opinion, is within the PHP driver, because I've never had trouble with the JDBC drivers.


DataMapper 1.6.0 - El Forum - 10-09-2008

[eluser]stensi[/eluser]
1:
Thanks for pointing the delete issue out. I hadn't noticed that I didn't switch the delete() method over to use _get_relationship_table(). This looks like it will only affect people using prefixes.

2:
I'll have a look at select_min/max/avg/sum to see what you mean. The likely fix will be to set as NULL if not set, so those working with Database fields that use NULL's can go ahead fine.

Code:
if (isset($row->{$field}))
{
    $item->{$field} = $row->{$field};
}
else
{
    $item->{$field} = NULL;
}

With the issue you're having for the insert (id being supplied as an empty string), that looks to be another one of those PostgreSQL only issues, since MySQL ignores the empty string in my tests (id setup as a AUTO INCREMENT, BIGINT).

_________________________

UPDATE

Just a note for everyone. The next version of DataMapper will be as a library. I'm making some changes to simplify a few things. The most notable will be in setting up the $has_many and $has_one relationships. Instead specifying the model => table, like so:

Code:
$has_one = array("country" => "countries", "group" => "groups");
$has_many = array("game" => "games");

You'll now just specify the model names:

Code:
$has_one = array("country", "group");
$has_many = array("game");