• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Returning standard objects with different queries

#1
[eluser]bapobap[/eluser]
Hi there,

So I have my models returning nice objects formatted in a particular way. Each MySQL query does not directly map to an object, so I basically get the query result, build the object and then return it. This works great for something like:

Code:
$this->User_model->user(123456)

which would return:

Code:
stdClass Object
(
    [id] => 2
    [username] => Peas
    [profile] => stdClass Object
        (
            [name] => Peas
            [email] => [email protected]
            [avatar] => 1
            [likes] => Green
            [dislikes] => Blue
        )
    [created] => 2009-01-01 00:00:00
    [updated] => 2009-01-01 00:00:00
)

It doesn't work well for other uses. Say I'm getting a list of users who have uploaded an image. I get a result from the image table in MySQL. It has a user_id column for me to JOIN and get the user record. If I were to use
Code:
$this->User_model->user($image->user_id)
for each image record, I'd be running an extra SQL query I didn't need, just to get my nicely formatted object back. What I'd prefer is for the user details I ask for in the image query to be formatted as it would be in the user model. To do this I need to copy and paste how the user object is built from the user model and apply it to this image result. So I'd get:

Code:
stdClass Object
(
    [id] => 2
    [width] => 320
    [height] => 240
        [user] => stdClass Object
             (
                [username] => Peas
                [profile] => stdClass Object
                    (
                        [name] => Peas
                        [email] => [email protected]
                        [avatar] => 1
                        [likes] => Green
                        [dislikes] => Blue
                    )
         [created] => 2009-01-01 00:00:00
         [updated] => 2009-01-01 00:00:00
             )

)

The fact I'm copying and pasting this for every sort of query I do that involves a user is a red flag. I know this isn't what I should be doing but I'm not sure what the solution is?

#2
[eluser]jedd[/eluser]
Hey, well done you for managing to slip the question mark in as the absolutely last character in your post! It certainly made it interesting to work out what your problem is.

If I may summarise, and ask you to clarify - your problem is that want to be able to present your data in a consistent format to your controllers, but without having to actually modify the format of that data as you retrieve it from disparate tables with necessarily disparate formats - is that right?

My approach to this alleged problem is two-fold. First, I use arrays rather than objects - I find they're easier to mung (to taste) before sending them back to the controller. Second, different functions obviously want different data, and different data necessarily will take on different formats based on its nature. Much like the CI core does, I try to write anything that might one day use multiple bits of data (even if today it only takes one piece) to work with an array of data types. That is, even if I know I have one item I'm playing with, if I think that my controller or view might one day want / be able to handle multiples, I'll ensure my model wraps the data into an array.

#3
[eluser]bapobap[/eluser]
Sorry, I guess it's hard to describe without code. A lot of much code to post here so trying my best!

A user record from MySQL looks like this:

Code:
stdClass Object
(
    [id] => 2
    [username] => Peas
    [password] => 73391d839fed4d8aba02b298ffcd5fdb6ccb7238
    [email] => [email protected]
    [name] => Peas
    [avatar] => 1
    [likes] => Green
    [dislikes] => dislikes
    [created] => 2009-01-01 00:00:00
    [updated] => 2009-01-01 00:00:00
)

To get a user I use:

Code:
$user = new User;
$user->user(123456);
$user = $user->user;

My User object, that all my views expect, looks like this:

Code:
stdClass Object
(
    [id] => 2
    [username] => Peas
    [profile] => stdClass Object
        (
            [name] => Peas
            [email] => [email protected]
            [avatar] => 1
            [likes] => Green
            [dislikes] => Blue
        )
    [created] => 2009-01-01 00:00:00
    [updated] => 2009-01-01 00:00:00
)

I do this because the User model allows to me add stuff to the returned object on an ad-hoc basis. For instance, a users preferences may be stored in another table. For most of the site, I don't need this information, so no need to run the query to ask for it. If I do though, I just add in another method call:

Code:
$user = new User;
$user->user(123456);
$user->preferences();
$user = $user->user;

And I get:

Code:
stdClass Object
(
    [id] => 2
    [username] => Peas
    [profile] => stdClass Object
        (
            [name] => Peas
            [email] => [email protected]
            [avatar] => 1
            [likes] => Green
            [dislikes] => Blue
        )
    [preferences] => stdClass Object
     (
         [background_color] => #000
         [text_color] => #fff
         [image] => spooky.jpg
     )
    [created] => 2009-01-01 00:00:00
    [updated] => 2009-01-01 00:00:00
)

Now. Let's say I want to get some data that has a user_id foreign key. Let's use tweets as an example.

Code:
stdClass Object
(
    [id] => 20983428
    [user_id] => 123456
    [tweet] => Happy halloween!
    [date] => 2009-10-31 15:00:00
)

Now I can either use that user_id and in my foreach going through all the tweets, ask my User model for the users record, formatted as my nice user object. This however means I'm running an extra query for each tweet. Not very good.

I JOIN on the user_id and get:

Code:
stdClass Object
(
    [user_id] => 123456
    [username] => Peas
    [email] => [email protected]
    [name] => Peas
    [avatar] => 1
    [likes] => Green
    [dislikes] => dislikes
    [id] => 20983428
    [tweet] => Happy halloween!
    [date] => 2009-10-31 15:00:00
)

but it's not formatted in my nice user object way. What I now need to do is format that to get:

Code:
stdClass Object
(
    [user] => stdClass Object
    (
        [id] => 123456
        [username] => Peas
        [profile] => stdClass Object
            (
                [name] => Peas
                [email] => [email protected]
                [avatar] => 1
                [likes] => Green
                [dislikes] => Blue
            )
        [created] => 2009-01-01 00:00:00
        [updated] => 2009-01-01 00:00:00
    )
    [id] => 20983428
    [message] => Happy halloween!
    [date] => 2009-10-31 15:00:00
)

I have to code this functionality everywhere I return user information to format everything into the way my controllers, libraries, helpers and views expect it.

What I'm wondering, is there some magic way to solve this I'm not aware of. For instance, does ORM solve this problem? If not, is there another solution?

Hope this helps explain things, probably not though!

#4
[eluser]jedd[/eluser]
Okay - big disclaimer - I'm not a fan of objects, and use them only when absolutely necessary.

CI's models are not usually treated as objects per se, at least not in the classic OO sense, or even the way that other frameworks, or OO-savvy PHP programmers would use them.

The fact that you're doing a new User suggests you're using model slightly more objectively than most people do .. which leads me to ask why you don't just treat the model as your object, and rather than return your object (ie. send it back to the controller), just interact with attributes of your model directly. That is, have your attributes defined in your class up front, and have your get functions populate those. This means you can populate things sensibly - sure, it will take a little bit of code to put them in the right place and format them 'just so', but the whole thing will be nicely constrained within your model class, and to a lesser degree constrained and defined by your layout of your attributes there.

Would this be workable? If not, you'll have to hope that someone au fait with object manipulation will stop by soon Wink


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2021 MyBB Group.