CodeIgniter Forums
Populating an array of objects using CI's load->model() functionality - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forum-20.html)
+--- Forum: Archived Development & Programming (https://forum.codeigniter.com/forum-23.html)
+--- Thread: Populating an array of objects using CI's load->model() functionality (/thread-29782.html)



Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]paulkmoore[/eluser]
Hi all - newbie post, so please feel free to redirect me if appropriate

I am trying to create an array of objects each of which is an instantiation of a Model. For context, I am modelling financial transactions in a hierarchy with a typical header and details relationship.

I have a Model for the tx header, and a model for tx detail, where one tx header has many tx detail subordinates.

I'd like to create the tx header and create an array of tx detail objects to represent the 'full' transaction.

I can instantiate single instances of both models within the controller fine, but I'm struggling to load multiple tx detail objects.

If I've understood the CI internals correctly all Models loaded using the load->model construct are mapped to the CI superobject (which is a Singleton), and therefore each object will be unique by name. This is set out in Loader.php which allows for the object to be reference by a specified name (as per the excellent CI user guide) - however, the name is required to be a string and therefore I am unable to call the load->model with an array element for a name.

i.e. $this->load->model('my_tx_detail_model', "txd[3]"); (reasonably) fails.

Is this a limitation of the CI superobject (singleton) design choice (flowed through to Loader.php), or is there some other approach I could be using to instantiate multiple Model objects? I've seen some reference to splobjectstorage, but again not sure whether this reasonably fits with the CI singleton or not.

Many thanks in advance

Paul


Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]n0xie[/eluser]
Have you tried:
Code:
$txd = array('somename', 'someothername');
$this->load->model('my_tx_detail_model', $txd[0]);
$this->load->model('my_tx_detail_model', $txd[1]);

$this->somename->...
$this->someothername->...

Or maybe I didn't understand the question.


Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]Dan Horrigan[/eluser]
n0xie: I could be wrong, but I believe that the second load of the same model would just be a reference to the first...no?
EDIT: No, I was wrong, it creates a new object every time, provided you give it a different name each time.

Anyways, why would you want to do this? You wouldn't want to load the model multiple times. That is not efficient. You should have the detail model return all the details for a given header. It is easy and efficient:
Code:
//WARNING:  UNTESTED CODE  Intended as example only

class Program extends Controller
{
    function Program()
    {
        parent::Controller();
        $this->load->model('tx_header');
        $this->load->model('tx_detail');
    }

    //This loads all the details for a header
    function view_header($tx_header_id)
    {
        $details = $this->tx_detail->get_all($tx_header_id);
        $this->load->view('header', $details);
    }
}

// Your tx_detail model
class Tx_detail extends Model
{
    function Tx_detail()
    {
        parent::Model();
    }

    function get_all($tx_header_id)
    {
        $this->db->select('*')->from('tx_details')->where('parent_tx', $tx_header_id);
        return $this->db->get();
    }
}

You could also create 2 libraries (not models), one called TxHeader and the other TxDetail. Then the TxHeader can contain an array of TxDetail objects.

Either way is better than trying to load the same model a bunch of times.

Dan


Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]paulkmoore[/eluser]
n0xie / Dan

Many thanks for the prompt replies - I really appreciate it.

Addressing the responses somewhat in turn:

n0xie - this would and does work but requires me to define the array of strings up front. I'm trying to load a number of detail records and don't know how many I'll have in advance. I appreciate that this would give the load->model function a string to work with however.

Dan - agree with your EDIT - the Loader.php allows for a unique name. To respond to the 'why would you want to do this point' I am using the models as objects to represent the table rows. i.e. each model has a set of properties (the columns from the table) and methods to get/set from the database, and any other methods appropriate to the object.

I hear (somewhat) the point about efficiency but to be honest the Model doesn't seem to be much overhead (given analysis of the Loader.php) and frankly if I create other objects that then instantiate the model(s) I'll be in a not dissimilar position.

I am trying to create something of a container class that will manage the header and multiple details records, and frankly I'm not sure whether this should be a Model or not. It's certainly not a Controller and doesn't feel like a library. Perhaps I should create a business_objects directory or similar - but I somewhat concerned about moving from the existing MVC primitives.

I'll take a more detailed look at your proposed example and get back to you.

Thanks both

Paul


Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]Dan Horrigan[/eluser]
[quote author="paulkmoore" date="1271885581"]n0xie / Dan
I am trying to create something of a container class that will manage the header and multiple details records, and frankly I'm not sure whether this should be a Model or not. It's certainly not a Controller and doesn't feel like a library. Perhaps I should create a business_objects directory or similar - but I somewhat concerned about moving from the existing MVC primitives.
[/quote]

A library is your best bet (a library is just a fancy name for a class anyway). Create a Details class that has all the properties you need. Then your container class can have an array of Detail classes. Each Details object would be a row from the database. The libraries can access the models that actually interface with the db (as long as you use use the get_instance() function).

Because the 2 classes are so closely tied, you can keep them both in the same file, that way you just load 1 library into your controller.

Dan


Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]vitoco[/eluser]
[quote author="Dan Horrigan" date="1271886118"]
A library is your best bet (a library is just a fancy name for a class anyway). Create a Details class that has all the properties you need. Then your container class can have an array of Detail classes. Each Details object would be a row from the database. The libraries can access the models that actually interface with the db (as long as you use use the get_instance() function).

Because the 2 classes are so closely tied, you can keep them both in the same file, that way you just load 1 library into your controller.

Dan[/quote]

Why use get_instance() from a library in order to access databases, if models do that with $this->db ??.

I think, that you must use one Model, or in the worst case, extends one model from the other, so you can get access to db, and return the data as you need.

MODEL 1
Code:
Class MTx_detail extends Model
{
    function MT_detail()
    {
        parent::Model();
    }

    function get_detail_tx()
    {
        ;
    }
}
MODEL 2
Code:
Class MTx extends MTx_detail
{
    function MTx()
    {
        parent::MTx_detail();
    }

    function get_header_tx()
    {
        ....
        ....
    }

    function get_data_tx()
    {
        .....
        $tx->header  = $this->get_header_tx();
        $tx->details = $this->get_detail_tx();
        ....
        return $tx ;
    }
}



IN THE CONTROLLER
Code:
...
$this->load->model('mtx_detail');
$this->load->model('mtx');
//
$tx = $this->mtx->get_data_tx();
...



Populating an array of objects using CI's load->model() functionality - El Forum - 04-21-2010

[eluser]Dan Horrigan[/eluser]
I should have worded my response better. You wouldn't access the db directly from the library, you would still use a model, you would just call the model methods from the library.

On your examples you gave...I do not agree, however, that does not make it wrong. It is just not my style. If you are going to go strictly models, I would do as I did in my original post.

I am done with this topic. Paul, there are a million ways to skin a cat, so pick the way that fits your style best and go for it (not skin a cat...that is just a metaphor :-)).

Dan


Populating an array of objects using CI's load->model() functionality - El Forum - 04-27-2010

[eluser]paulkmoore[/eluser]
Dan et al

Thanks for all the feedback - I really appreciate it. Here's what I have concluded:

The reason I was getting into a mess with i) multiple instances of Models and ii) hierarchies of Models is that I was trying to implement object aggregation of the Transaction header and details exclusively within the MVC framework. Understanding (thanks Dan) that I could and should maintain these objects elsewhere and utilise them in the MVC framework was the leap I had missed (looks simple in retrospect!).

So here's what I have ended up with in pseuso code:

Code:
class Transaction_object
{
//Common properties

public $details = array();  // holder for the tx details objects

}

class Transaction_type_1_object extends Transaction_object
{
//Properties specific to this type of transaction

//Method overload where required from the base class
}

class Transaction_type_2_object extends Transaction_object {}

class Transaction_type_3_object extends Transaction_object {} // etc etc

class Transaction_detail_object
{
//Common properties
}

class Transaction_detail_type_1_object extends Transaction_detail_object {}

class Transaction_detail_type_2_object extends Transaction_detail_object {}  // etc etc

This allows flexible arrangements of the transaction header and details without coupling too tightly, and the extended classes allow good precision in terms of the object properties and methods i.e. I can really lock these down.

I chose not to implement as CI libraries in the end as the loader.php calls the constructor on load, which wasn't appropriate in all cases. Usage of a require_once where I want to use the objects works well however.

Thanks again to all for the help

Best regards

Paul


Populating an array of objects using CI's load->model() functionality - El Forum - 08-02-2010

[eluser]tunesmith[/eluser]
If you instantiate objects from a library, but the library calls the model's db routines, then doesn't the library have to have a CI instance as an instance var? So wouldn't instantiating multiple library objects be just as inefficient as instantiated multiple model objects?

I suppose it's possible to have it both ways by doing get_instance not in the constructor, but in every function that needs it...