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

[eluser]Boyz26[/eluser]
That WORKED!! Awesome! Thanks!

(I removed the other models from autoload.)


DataMapper 1.6.0 - El Forum - 10-06-2008

[eluser]stensi[/eluser]
@Boyz26: Cool, glad to be of help :-)

@paul Apostol: Here's a quick change you can do to the __autoload() function in DataMapper, to load models in sub-directories.

Code:
/**
* Autoload
*
* Autoloads object classes that are used with DataMapper.
*
* Note:
* It is important that they are autoloaded as loading them manually with
* CodeIgniter's loader class will cause DataMapper's __get and __set functions
* to not function.
*
* @access    public
* @param    string
* @return    void
*/
function __autoload($name)
{
    $file = APPPATH . 'models/' . strtolower($name) . '.php';

    if (file_exists($file))
    {
        require_once($file);
    }
    else
    {
        if ($handle = opendir(APPPATH . 'models'))
        {
            while (FALSE !== ($dir = readdir($handle)))
            {
                $file = APPPATH . 'models/' . $dir . '/' . strtolower($name) . '.php';

                if (strpos($dir, '.') === FALSE && file_exists($file))
                {
                    require_once($file);

                    break;
                }
            }

            closedir($handle);
        }
    }
}

This will load the first match it finds in the "models" directory. For example, if you have a User model in the "models" directory it will be loaded. If not, it will check the sub-directories of "models" to try and find it in there (it only goes down one level). If you have a User model in sub-directory "a" and a User model in sub-directory "b", then the version in "a" will be loaded.

Note that you cannot load more than one model of the same name so you shouldn't have multiple models of the same name.


Anyone else interested in this becoming a standard part of DataMapper? Possibly with a recursive look at the sub-directories of the "models" directory, if the model is not found in the "models" directory itself?


DataMapper 1.6.0 - El Forum - 10-06-2008

[eluser]BaRzO[/eluser]
Hi stensi,
I am following your posts, and still playing & learning DM, Thanks for all...
So the sub-directory issue is would be good...
IMO DM should be simple and fast(light-weight)


DataMapper 1.6.0 - El Forum - 10-06-2008

[eluser]wiredesignz[/eluser]
@stensi, Could you try using spl_autoload_register instead of __autoload. There are many good reasons not to use __autoload, but the biggest I see is compatibility with other php5 libraries which also autoload their own class files.


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]stensi[/eluser]
Good suggestion, thanks. What about people who don't have the SPL module enabled though? I've no idea on the possible number of people who don't have it, but if it's likely to be a substantial number, then I'd like to cater for that scenario. In which case, how would you do it?

My initial thoughts:

Code:
if (function_exists('spl_autoload_register'))
{
    // 'autoload' would be a static function in the DataMapper class
    // that has the same code as my current __autoload function
    sql_autoload_register(array('DataMapper', 'autoload'));
}
else
{
    function __autoload($name)
    {
        // Same code as my current __autoload function
    }
}

I'm not entirely happy with that solution though, since it means having the same autoloading code in 2 places Undecided

If the number of people without SPL is low then I'll just switch over the spl_auto_load_register completely (would be easier).


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]Maxximus[/eluser]
Hi Stensi, like your Datamapper a lot. I made it a library (think it should not be a model), and changed your autoload function too to search in Modular Extension model directories.

SPL will be enabled for everyone using PHP5, and since the whole lot will not work without PHP5 I think it might be a good idea to make it fully PHP5 anyway.

Datamapper as a library is here: http://snipr.com/45aep . To make this work, save it in libraries, remove it as an autoloaded model, add it to the autoloaded libraries, and add inflector to helpers.

Might need some additional changes but your supplied demo works with it (as ME module too).


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]wiredesignz[/eluser]
[quote author="Maxximus" date="1223397924"]SPL will be enabled for everyone using PHP5[/quote]
@Stensi, This is correct.

Note: Your autoload should be a public static function autoload() as per Maxximus example.


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]Paul Apostol[/eluser]
@stensi Thank you very much for the solution.

For what I needed I make this changes (not fully tested, so, be carefully):
- definition of the model
Code:
var $table = "table1";
var $table_prefix = "prefix1";
var $has_many = array('module2' => Array(
            'table'=>'table2', 'table_prefix'=>'prefix2',
            'join_prefix'=>'prefixJ', 'id'=> 'idName'));

function changed:
Code:
function _get_relationship_table($table, $model)
    {
        $relationship_table = '';

        // Check if self referencing
        $table_ref = str_replace($this->table_prefix, '', $this->table);
        if ($table_ref == $table)
        {
            $relationship_table = (plural($this->model) < plural($model)) ? plural($this->model) . '_' . plural($model) : plural($model) . '_' . plural($this->model);
        }
        else
        {
            $relationship_table = ($table_ref < $table) ? $table_ref . '_' . $table : $table . '_' . $table_ref;
        }

        return $relationship_table;
    }

Code:
function _related($table_in, $model, $id)
    {
        // No related items
        if (empty($table_in) || empty($model) || empty($id))
        {
            return;
        }
        if(!is_array($table_in)){
            $table = plural($table_in);

                
        } else {
            $table = $table_in['table_prefix'] . $table_in['table'];
                
        }
        if (empty($model))
        {
            $model = singular($table);
        }
        $this->model = strtolower($this->model);

        // Determine relationship table name
        $relationship_table = $this->_get_relationship_table($table, $model);

        // Retrieve related records
        if (empty($this->db->ar_select))
        {
            $this->db->select($this->table . '.*');
        }
        
        if(is_array($table_in) && !empty($table_in['id'])){
            $table_ref = str_replace($this->table_prefix, '', $this->table);
            $relationship_table = $this->_get_relationship_table($table_in['table'], $model);
            if ($table_ref == $table)
            {
                $this->db->from($table_ref);
                $this->db->join($relationship_table, $table . '.'.$table_in['id'].' = ' . $this->model . '_'.$table_in['id'], 'left');
                $this->db->where($relationship_table . '.' . $model . '_'.$table_in['id'].' = ' . $id);
            }
            else
            {
                $this->db->from($this->table);
                $this->db->join($table_in['table_prefix'].$relationship_table, $this->table . '.'.$table_in['id'].' = ' . $this->model . '_'.$table_in['id'], 'left');
                $this->db->join($table, $table . '.'.$table_in['id'].' = ' . $model . '_'.$table_in['id'], 'left');
                $this->db->where($table . '.'.$table_in['id'].' = ' . $id);
            }
        } else {
            // Check if self referencing
            if ($this->table == $table)
            {
                $this->db->from($this->table);
                $this->db->join($relationship_table, $table . '.id = ' . $this->model . '_id', 'left');
                $this->db->where($relationship_table . '.' . $model . '_id = ' . $id);
            }
            else
            {
                $this->db->from($this->table);
                $this->db->join($relationship_table, $this->table . '.id = ' . $this->model . '_id', 'left');
                $this->db->join($table, $table . '.id = ' . $model . '_id', 'left');
                $this->db->where($table . '.id = ' . $id);
            }
        }
        $query = $this->db->get();

        $this->model = ucfirst($this->model);

        // Clear this object to make way for new data
        $this->_clear(TRUE);

        if ($query->num_rows() > 0)
        {
            // Populate all with records as objects
            $this->all = $this->_to_object($query->result(), $this->model, $this->fields);

            // Populate this object with values from first record
            foreach ($query->row() as $key => $value)
            {
                $this->{$key} = $value;
            }
        }

    }


@stensi: now I'll have with 50% more tables (because of your datamapper) Big Grin but it's fine. I know that is some more things to set but I prefer to use prefixes for a easier use. This is my solution for the moment, maybe with some errors Wink . Some of the tables have a prefix, some others tables another, also some of the joining tables will be with one of the prefixes.


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]Boyz26[/eluser]
Question:

Will datamapper slow an application down a lot?

Thanks!


DataMapper 1.6.0 - El Forum - 10-07-2008

[eluser]stensi[/eluser]
@Maxximus, @wiredesignz: Cool, thanks for that. I'll switch over to the spl_autoload_register completely. And good to know it's compatible with Modular Extensions :-)

@paul Apostol: It looks like our approach at implementing prefixes is very different. Your solution seems to be more customised to your particular situation, which is good for you Wink but it looks like there's more work involved when setting up the $has_many and $has_one relationships.

So far, I've got it setup so you can set a prefix once in the main DataMapper file, which then applies to all DataMapped models. You can override that prefix in your DataMapped models though, so you can have different prefixes in one or more of them, if required. With the way I'm doing it, it's not necessary to define the prefixes in the $has_many and $has_one relationships as setting it for the models themselves is enough. It'll be easier for me to explain what I mean when I have it finished up and ready for you all.

@Boyz26: I've done testing both locally and on my production server and found the performance to be pretty much the same as doing it all directly with CodeIgniter's ActiveRecord class (which DataMapper uses heavily).

DataMapper has a slight overhead because of the extra class instances involved but other than that, the results are quite close. So no, it shouldn't slow an application down.

If you'd like to do some testing yourself, the Profiler is quite handy.

I'll see if I can find the exact tests I ran and upload it with the results.