That WORKED!! Awesome! Thanks!
(I removed the other models from autoload.)
This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.
The active forums are here.
September 05, 2008 12:32pm
Subscribe [115]#91 / Oct 06, 2008 8:51pm
That WORKED!! Awesome! Thanks!
(I removed the other models from autoload.)
#92 / Oct 06, 2008 8:52pm
@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.
/**
* 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?
#93 / Oct 07, 2008 12:32am
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)
#94 / Oct 07, 2008 1:43am
@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.
#95 / Oct 07, 2008 7:55am
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:
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 😕
If the number of people without SPL is low then I’ll just switch over the spl_auto_load_register completely (would be easier).
#96 / Oct 07, 2008 8:45am
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).
#97 / Oct 07, 2008 2:17pm
SPL will be enabled for everyone using PHP5
@Stensi, This is correct.
Note: Your autoload should be a public static function autoload() as per Maxximus example.
#98 / Oct 07, 2008 3:47pm
@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
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:
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;
}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) :D 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 😉 . Some of the tables have a prefix, some others tables another, also some of the joining tables will be with one of the prefixes.
#99 / Oct 07, 2008 5:24pm
Question:
Will datamapper slow an application down a lot?
Thanks!
#100 / Oct 07, 2008 6:03pm
@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 😉 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.
#101 / Oct 07, 2008 7:33pm
I’ve been following this thread and reading along (but havent take the plunge to DM yet). This is really a great tool to simplify daily CRUD functionalities a coder always encounters 😊 Also thanks a lot for actively participating and patiently answering everyone’s question .. Keep it up!
I have some concerns though..
In our database we have 300+ tables so creating join tables will definitely double its size (600+ !),, do you also plan to support tables that uses foreign keys instead of table joins?
DM is quite similar to Rails’ Active Record,although in AR if you have legacy tables you can specify the table name and the primary key of the those legacy tables without having to alter the table itself. It would be great if DM can have this functionality- do you also plan to do this?
Thanks a lot!
r2
#102 / Oct 07, 2008 7:55pm
Thanks r2 😊 I know how frustrating it can be to start using a library but having little support on how to use it, so if I have time spare to help, I will.
I thought Paul’s 60 tables was a lot… but 300, lol!
At the moment I have no plans to support foreign keys but that doesn’t mean I wont look at including it down the road. I expect I’ll get around to it eventually as I’ve had enough people ask for it.
Right now I’m finishing off the ability to have table prefixing, and the documentation to accompany it, as well as documenting some of my other libraries for release. I’ve got quite a few sitting around that should be useful to others, although some of them will take me a while to finalise.
I’ll see if I can include the ability to rename the primary key (“id” field), for those with legacy tables, while finishing off the table prefixing. It should use the same premise.
#103 / Oct 07, 2008 8:26pm
Cool stensi, good to see you are really active with this. I hope you consider transforming this to a library, and PHP5 it all the way, and saves some E_STRICT warnings.
Besides that, could you add count(*) (with an alias) to the options? Can be handy for the order_by. Thanks!
#104 / Oct 08, 2008 3:29am
@Maxxiumus: I’d actually meant to include a count() method in the past couple of versions (including the latest) but it keeps slipping my mind, lol!
I’m not sure about making it a library just yet. I can see some benefits, such as being able to autoload settings from a config file straight in but other than that, I haven’t thought up a real reason to switch. Convince me why you think it would be better as a library and I’ll consider it 😉
Version 1.3.4 has been released!
View the Change Log to see what’s changed.
In short, table prefixing is now possible, including the ability to give joining tables a different prefix (read Setting up Table Prefixes for more information). Autoloading of classes has been improved so it plays nice with other autoloading PHP5 libraries. Also, it now performs a recursive search of the models directory, if the class being auto-loaded is not found in the models directory. This means you can sort your classes into sub-directories inside the models directory if desired.
There’s a few other changes and improvements as well.
Enjoy 😊
#105 / Oct 08, 2008 3:46am
DM should be a library for many reasons, the first being that CI’s Model class is a waste of space really and has nothing to offer us other than re-assigning the CI controller libraries to a new object, the CI model may as well be another controller.
DM is a fine replacement for the CI model class, but because it is never instantiated alone and it cannot really be a defined as a model.
In fact the CI method of loading models suits datamapper better as a library than you have at present. I’ll add more on this subject later. But in the meantime stensi, keep up the fine work.