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-10-2008

[eluser]stensi[/eluser]
Not sure how this breaks timestamps (except if you just mean timestamp settings from the config aren't being applied).

I'll change it to specifically load the config file. Have you come across any other issues yet?


DataMapper 1.6.0 - El Forum - 10-10-2008

[eluser]OverZealous[/eluser]
AH-HA: I almost reported this, but I forgot you said to change the relationship arrays. I must update that to continue...


DataMapper 1.6.0 - El Forum - 10-10-2008

[eluser]stensi[/eluser]
Version 1.4.1 has been released!

View the Change Log to see what's changed.

In short, I changed it so the autoload of the configuration file is explicit.

Thanks for bringing that to my attention Phil :-)


DataMapper 1.6.0 - El Forum - 10-10-2008

[eluser]OverZealous[/eluser]
I've been thinking about a way to fix the PostGreSQL insert bugs that will also allow default values from the database to show through. It isn't too horrible, I promise!

The idea would be to capture a collection of "changed" fields from within the __set() method. Then, when building the $data array, only include those items that were changed.
Code:
// at top
var $_changed_fields = array();

function __set($name, $value)
{
    $this->{$name} = $value;
    // Added these three lines
    if(in_array($name, $this->fields))
    {
        array_push($this->_changed_fields, $name);
    }
}

function _to_array($validate = FALSE)
{
    $data = array();

    foreach($this->fields as $field)
    {
        // Added this line, and updated the if()
        $changed = in_array($field, $this->_changed_fields);
        if ($changed && empty($this->{$field}) && $validate)
        {
            continue;
        }
            
        $data[$field] = $this->{$field};
    }
        
    return $data;
}

// Added new function, needs to be called in get() and _clear()
function _clear_changed_fields($all = FALSE)
{
    $this->_changed_fields = array();
}

/* Also the save() method will need to be changed to user $this->id
* for the check and to pass into the update's where.
* There is no reason to ever put the [id] into the query
* since it is auto-generated, and shouldn't change for updates.
*/

Now, updates and inserts will be limited to those fields that get set between get() and save(). This would reduce some DB traffic, and also provide cleaner inserts in general.

So, does that make sense? Would it break anything on the MySQL end? It would help me eliminate my only remaining hacks - default values and removing the id. Then PostGreSQL (using smallints instead of booleans) should work fine, at least, so far as I've noticed.


DataMapper 1.6.0 - El Forum - 10-11-2008

[eluser]Maxximus[/eluser]
Thanks stensi, works brilliant as a library.

To make the autoload working for Modular Extensions, I've applied a small patch to this class. Since it wouldn't hurt non-ME users, perhaps it can be in a next version.

Code:
public static function autoload($class)
    {
        /* don't try to autoload CI_ or MY_ prefixed classes */
        if (strstr($class, 'CI_') OR strstr($class, 'MY_')) return;
        
       // Prepare class
        $class = strtolower($class);

        // Prepare path
        $path = APPPATH . 'models';

        // Prepare file
        $file = $path . '/' . $class . EXT;

        // Check if file exists, require_once if it does
        if (file_exists($file))
        {
            require_once($file);
        }
        else
        {
            // Look in ME Model directories
            if (defined('MODBASE')) {
                $paths = glob(MODBASE . '*/models/' . strtolower($class) . EXT, GLOB_NOSORT);
        
                if (file_exists($paths[0]))
                {
                    require_once($paths[0]);
                    return;
                }
            }
            // Still not found: Do a recursive search of the path for the class
            DataMapper::recursive_require_once($class, $path);
        }
    }



DataMapper 1.6.0 - El Forum - 10-11-2008

[eluser]Maxximus[/eluser]
For those who use KHCache (a very nice caching system), and want to cut on the expensive list_fields method, change line 105 in DataMapper to:

Code:
// Get and store the table field names
        if (KH_CACHE) {
            $key = $this->khcache->generatekey(__CLASS__, __FUNCTION__, $this->table);
            if (($data = $this->khcache->fetch($key)) !== false) {
                $this->fields = $data;
            }
            else
            {
                $this->fields = $this->db->list_fields($this->table);
                $this->khcache->store($key, $this->fields);
            }
        }
        else
        {
            $this->fields = $this->db->list_fields($this->table);
        }

To use KHCache for your other queries too, there is a bit more needed, but if it really works it would be great.

*Rethinking* Perhaps better to alter the AR cache method...

For that reason I created a drop-in replacement for DB_cache.php. See KHCache.


DataMapper 1.6.0 - El Forum - 10-11-2008

[eluser]stensi[/eluser]
@OverZealous.com: I can see what you're trying to achieve with that code and it's a good idea. Sending only the changed fields in an UPDATE would indeed save on the bandwidth and processing time over a longer period.

I've started testing a solution for this which is a little different to yours but with the same result (uses the existing _changed functions). If it tests ok, I'll include it in the next version. I've got a very large list of things I want to include/improve now, which keeps growing, so it's now just a matter of having the time to get around to it.

UPDATE

I've finally got a working solution for this that required very few changes. When you do a save to an existing object (update), only the changed fields will be sent in the Database query, making it much more efficient (thanks for pestering me to do this, lol!).

When saving a new object (insert), it will send everything except the id (which you should have as an AUTO INCREMENT field).

These changes should solve all the issues you were having with your PostgreSQL insert/update queries. It works fine for MySQL as well.


@Maxximus: Caching for things like that is definitely something I want to look at including in a later version and Neophyte's KhCache is an awesome library for that sort of thing. I'm not all that happy with the AR caching.

I haven't seen or used the glob() function before. Would it be more efficient for me to use that instead of the recursive_require_once I've created?

Oh, and I'll be including this code of yours in the next version as well Wink
Code:
/* don't try to autoload CI_ or MY_ prefixed classes */
if (strstr($class, 'CI_') OR strstr($class, 'MY_')) return;

UPDATE

So far, the next version just has the changes I've mentioned in this post. I might release that version later tonight and then go back through all the forum posts and compile a full list of requested additions/features, stick those in the list of things I'm already wanting to do, and then sort it out in order of most useful.

I'll probably post the top 10 items from that list so everyone can give some feedback on whether they would like them added in the way I envision or if they're prefer it done differently.


DataMapper 1.6.0 - El Forum - 10-12-2008

[eluser]stensi[/eluser]
Version 1.4.2 has been released!

View the Change Log to see what's changed.

In short, I improved the performance of the save method when updating an existing object, so it only updates the changed data. The autoload method no longer attempts to autoload CI_ or MY_ prefixed classes (so no recursive searching for classes that definitely wont exist in the models folder).

As I said above, I'll now be taking a look at all the requested additions/features people have posted here. However, I wont have as much time in the coming weeks since I'm going to Japan with my wife on holiday :-)

In the mean time, I welcome any new suggestions/feature requests for what you'd like to see in a future version of DataMapper!


DataMapper 1.6.0 - El Forum - 10-12-2008

[eluser]nfx-nano[/eluser]
Hello, and 'grats on an excellent library (+docs).

However, I believe it's missing an important function.

Example: user Fred has 100 computer items in stash.

The join table:
Code:
id - user_id - item_id - amount

There is no current way DataMapper can access the field amount from this join table. Sometimes I need to be able to add additional fields in the join table, and it would be great to be able call those fields with DataMapper, as such:

Code:
// Get Fred
$user = new User();
$user ->where('user_name', 'Fred')->get();

// Get the computer items
$user->item->where('item_name', 'computers')->get();

// Show amount of computers related to Fred
echo '<p>' . $user->item->amount . '</p>';

I wouldn't mind being able to do this either:

Code:
// Get the related items
$user->item->where('amount', '100')->get();



DataMapper 1.6.0 - El Forum - 10-12-2008

[eluser]ntheorist[/eluser]
hi, thanks for this great library!

forgive me if this topic has been covered before.. regarding the validation, is there a way to bypass certain validation rules if the field is not required?

for instance:
Code:
array(
     'field' => 'zip',
     'type'  => 'numeric',
     'label' => 'Zip',
     'rules' => array('trim','numeric')
),
array(
     'field' => 'email',
     'type'  => 'email',
     'label' => 'Email',
     'rules' => array('trim','valid_email','max_length'=>120)
),

Neither field has 'required' in their rules, but because they fail the numeric and valid_email tests with empty values, the datamap doesn't save and an error is generated, therefore essentially requiring them. But of course, i don't want to remove the numeric/valid_email tests altogether..

I suppose i could try having the validation test check if there's a value, and if not then it would suppress all tests besides 'required', but before i go messing up your code i thought i'd ask here, since this issue may have been resolved already and i just couldn't find it.

thx,

CC