[eluser]esbium[/eluser]
Coming from a Java world where we have things like Hibernate for ORM, I have taken the persistence layer for granted for a while now. I recently started developing a php app on CI and found the ActiveRecord library in the Wiki. Its great and its probably only going to get better. One thing I found that I don't like though is that it only supports 1-1 relationships with a pivot table.
I developed an extension to that library to handle normalized 1-1 relationships and thought I would post it here to get feedback, ideas, etc. This is just the start of it and I have only tested it with a few relationships. They seem to work though.
Keep in mind while reading this post that I have been a Java developer for years but just recently started working with PHP professionally. It has been a hobby for a few years though. If you see mistakes in my code, please don't hesitate to point them out!
Enough chatter! Here is the __call function in the ActiveRecordEnhanced class:
Code:
public function __call($method, $args)
{
if(stristr($method, 'fetch_1to1_')) return $this->_fetch_one_to_one(str_replace('fetch_1to1_', '', $method), $args);
//if not one of our new methods, call the original
return parent::__call($method, $args);
}
And here is the private _fetch_one_to_one function:
Code:
private function _fetch_one_to_one($oneToOneTable, $args)
{
//TODO this will break for person/people etc.. Find a way to load the other model and get its _table attribute, maybe...
$relationshipTable = $oneToOneTable . 's';
$query = $this->db->query('
SELECT
' . $relationshipTable . '.*
FROM
' . $relationshipTable . '
WHERE
' . $relationshipTable . '.id = ' . eval('return $this->' . $oneToOneTable . '_id;')
);
eval('$this->' . $oneToOneTable . ' = $query->row();');
//TODO, what do we do if it returns no results?
if(empty($this->$oneToOneTable))
$this->$oneToOneTable = new stdClass();
}
So, given a data relationship like Task -> Project, meaning each Task has a parent Project, and the Task table has a column like 'project_id', I can now write code like this:
Code:
$task = $this->load->model('task');
$tasks = $this->task->find(ALL);
foreach($tasks as $tsk)
{
echo "Task name = " . $tsk->name . '<br/>';
//load the parent project
$tsk->fetch_1to1_project();
echo 'Parent Project name: ' . $tsk->project->name;
}
What does the CI community think? Am I on the right track? Also, am I duplicating efforts? I don't want to use ORM solutions like Propel or Doctrine, I have my reasons.
Let me know!!