Welcome Guest, Not a member yet? Register   Sign In
Is there a better way to prevent active record collisions?
#1

[eluser]Denzel[/eluser]
Maybe I'm doing something the wrong way, I've only been using this framework for a month.

The Problem
Code:
class news_model extends CI_Model {
public function __construct() {
  parent::__construct();
  $this->load->database('news');
}

public function get_news() {
  // blah
}
}

class comments_model extends CI_Model {
public function __construct() {
  parent::__construct();
  $this->load->database('comments');
}

public function get_comments() {
  // blah
}
}

class ultra_controller extends CI_Controller {
public function __construct() {
  parent::__construct();
  $this->load->model('news_model');
  $this->load->model('comments_model');
  
  // COLLISION
  $this->news_model->get_news();
}
}
As you can see, due to the use of active records, get_news will attempt to execute upon the comments database.

My Solution
Code:
class news_model extends CI_Model {
protected $db = NULL;
public function __construct() {
  parent::__construct();
  $CI =& get_instance();
  $CI->news_db = $this->load->database('news');
  $this->db =& $CI->news_db;
}

public function get_news() {
  // blah
}
}

class comments_model extends CI_Model {
protected $db = NULL;
public function __construct() {
  parent::__construct();
  $CI =& get_instance();
  $CI->comments_db = $this->load->database('comments');
  $this->db =& $CI->comments_db;
}

public function get_comments() {
  // blah
}
}

class ultra_controller extends CI_Controller {
public function __construct() {
  parent::__construct();
  $this->load->model('news_model');
  $this->load->model('comments_model');
  
  // PEACHY
  $this->news_model->get_news();
}
}
This is how I alleviate the problem. Note, I add a member variable to CodeIgniter to retain profiling data. (CodeIgniter finds open database connections through reflection.) Am I going about this the wrong way, or is this simply a valid workaround for an active record limitation? Thanks.
#2

[eluser]Aken[/eluser]
You can just use the return parameter of $this->load->database() to load each DB into a local model property. Using get_instance() in your model is unnecessary, since extending CI_Model already gives you the CI superobject using $this.

Code:
class Comments_model extends CI_Model {

protected $db;

public function __construct()
{
  parent::__construct();
  
  $this->db = $this->load->database('comments', true);
}

// ...

}
#3

[eluser]Aken[/eluser]
And it's also worth mentioning that perhaps your database could be better optimized so that you only need a single connection. Depends on your situation.
#4

[eluser]Denzel[/eluser]
You would think that code is correct, Aken, but I tried that already. The information will not be mined by the profiler. Although getting properties is mapped to the superobject, setting properties is not. From system/core/Model.php:
Code:
function __get($key)
{
$CI =& get_instance();
return $CI->$key;
}
There is no magic set method, therefore I must manually assign the property to the superobject. Thanks for the suggestion though.

Furthermore, yes, I have considered concatenating databases but as it stands now I can't do that.
#5

[eluser]Aken[/eluser]
I'm aware there's no setter method, but why would you need one? I don't see why you would need to assign the returned database to the CI object before you can use it in your model. That's the point of using the return parameter of $this->load->database().

I will look into actually testing this later, but give that a shot. If it doesn't work, post specifically where it doesn't, because from what I can tell it should.
#6

[eluser]Denzel[/eluser]
You're missing the point. The database works fine, the profiler does not. The profiler scraps active database connections from the CI superobject in system/libraries/Profiler.php::_compile_queries like so:
Code:
// Let's determine which databases are currently connected to
  foreach (get_object_vars($this->CI) as $CI_object)
  {
   if (is_object($CI_object) && is_subclass_of(get_class($CI_object), 'CI_DB') )
   {
    $dbs[] = $CI_object;
   }
  }
An open connection on a local $db property in a CI_Model is not found by the profiler! Hence my original post:
Quote:Note, I add a member variable to CodeIgniter to retain profiling data. (CodeIgniter finds open database connections through reflection.)
Maybe I should have restated my question. "Is there a better way to prevent active record collisions while retaining profiling data?"

I appreciate the help a great deal Aken.
#7

[eluser]Aken[/eluser]
Aha! I missed that text underneath your code block.

In that case, I don't see anything specifically wrong with your code. You'll want to make sure that you don't have any naming collisions with other libraries and whatnot.

You might also consider creating a new base model (MY_Model) and adding a setter method (magic or otherwise), to create a more universal way of adding to the super object / profiler.
#8

[eluser]Denzel[/eluser]
Great! That's what I was planning to do. Just wanted to confirm the notion that I wasn't overlooking some other blindingly simple way to accomplish this with CodeIgniter. Thanks Aken!
#9

[eluser]Aken[/eluser]
Yeah, as far as I know there's no already-established method of making this easier. You're welcome!




Theme © iAndrew 2016 - Forum software by © MyBB