Welcome Guest, Not a member yet? Register   Sign In
Libraries or Models, favouritism?
#1

[eluser]Hyra[/eluser]
Hey hey,

So i'm (still) in the progress of porting my existing community site to CI. Big fun (actually, it is, really!)

Although i'm running into some issues and decided to take a step back and think things over.

Currently i'm having 2 issues which, i think, cover all related bottlenecks.

First up .. controllers.

Let's take an example .. At the site people can visit other users and see, for example, their Profile, Gallery and Blog. In return, people can maintain their own Profile and Blog.

Following set of controllers with methods could be used:

For the users (artists) people can visit:
Code:
artist.php -> index() (profile)
           -> blog()
           -> blog_entry($id)
           -> gallery()
           -> artwork($id)
.. more for adding comments on an artwork, comment the profile page, etc. etc.

Then, for the user himself, to maintain his blog:
Code:
my_blog.php   -> index() (profile)
              -> add()
              -> edit($id)
              -> delete()
Many more controllers like above, for maintaining artworks (my_artwork.php) and so on.

Now, this seems, and in fact is, a bit cumbersome. Lots of repetive tasks within the controllers, but for other parts of the site. I.e. add a comment to an artwork, or on a blog entry.

Of course, an option would be to group all those methods into one controller, but this would make the code even less maintainable/overviewable.


Extending on this, there's "issue" number 2: Models or Libraries.

Let's take the blog entries as the same example. Would it be wise to create a library "blog" which has methods for just about anything? Meaning: create an entry, handle editing and comments by other visitors, etc. Or would that classify as a model. Or even a combination? I'm not sure what the best way to go is.

I'm finding it hard to define the difference between a model and a library other than what i can find throughout the documentation that a model would handle all the database actions, and a library is used for (complicated) tasks. But this would mean I would have to go with a combination of the 2, ending up with:

controller my_blog.php
library blog.php which handles business logic called from the controller
model blog.php (in fact not possible due to name conflicts) which handles database actions.

A library could do both database and "thinking" tasks, thus making the model obsolete. But .. wouldn't this be wierd?


So yes, I'm rambling now Smile

I could do with a chatroom on IRC (alas, the ports are closed at work) or someone to MSN with to discuss these things. Or maybe someone can make sense of the above and give me some pointers?
#2

[eluser]Michael Wales[/eluser]
Personally, I see a library as much more functionality than a model would support. A library could be anything (form validation, for example).

A model deals strictly with data. How do I get the data, how do I store it, how do I validate that particular piece of data.

I guess a good example would be - storing a user's phone number.

You would first extend CI's Validation library to support a phone_number validation option. This would more than likely utilize regex to ensure the phone number is in the format of #-###-###-####.

Now, for whatever reason, you are only wanting local users. So, for me, if that phone number doesn't start with 1-805, it's not valid. Sure - it's still a phone number, but it's not valid for this particular data entry. So, in the model - I would further validate that particular piece of data, and then save the information to the database.
#3

[eluser]jbowman[/eluser]
For your controller why not

Code:
artist.php -> index() (my profile, if no session, redirect to registration or front page)
           -> blog($uid = "use_session")
           -> blog_entry($id)
           -> gallery($uid = "use_session")
           -> artwork($id)
.. more for adding comments on an artwork, comment the profile page, etc. etc.

Play with routes a little and get blog/add, blog/del, and blog/edit...

For models vs libraries, I'll give you an example of what I'm working on now.

I have an idea I'm working on where my site is going to authenticate against a jabber server, and also get profile information from there.

So, I grabbed an existing jabber library I found, and modified it a little to turn it into an acceptable library for CI.

Then I created a jabber.php in my config folder which includes the jabber host and port information (more information may be added later, all I need right now). This then gets autoloaded.

Now, I'm working on my jabber_model.php. Literally started on this last night. Currently is has 1 and a half methods. The jabber library is loaded in the constructor.

connect() - uses the information from the config file to connect to a jabber server
authenticate($username, $password) - calls the connect method to establish a connection to the jabber server, then authenticates based on passed variables.

So, as you can see, the library holds all the advanced protocol implementations, where as my model runs on top of that to plug in and retrieve information. By using generic methods like "connect, authenticate (you know I should change this to log in), logout, etc etc", I can swap out models under my controllers if I decide that I really don't want to use jabber after all.
#4

[eluser]wiredesignz[/eluser]
Quote:A model deals strictly with data. How do I get the data, how do I store it, how do I validate that particular piece of data
Models are not strictly data, Models represent information describing something (a real world object perhaps), they can be data or otherwise, Models encapsulate the persistence layer, Yes, but they also provide business logic to describe the object they represent, and that can be anything.
#5

[eluser]ejangi[/eluser]
Continuing on from what wiredesignz is saying: An example would be if you're storing information in XML files instead of a DB. You could have a "Articles" model which doesn't call the $this->db methods, but uses an XML_Parser library to read the appropriate files and return the information as an array of objects (or such like).

I honestly think that the reason people get so confused about this stuff is because CI doesn't use Models the way it should. Instead it's just "another" abstraction layer, the same as libraries. Really what models should be doing is making a representation of the data it returns. For instance, in something like rails, the framework will actually return a Model object for each row of the database which includes all the properties of the DB table and also any methods that you want to perform on the row of data. This makes a lot more sense when you look at the whole idea of Object Oriented Programming. CI tends to use objects as a Namespace rather than a representation. Don't get me wrong, I like that things are name-spaced, but it could be improved.
#6

[eluser]Hyra[/eluser]
Thanks for the replies, it helps.

I think, for me, the confusing bit was where to put the logic. A controller should handle the logic.

1) Right, what data i get
2) What should i do with it
3) Anything i have to do with it before i dispatch it to the *put backend layer here*

Of course, there are repetitive actions, like Michaels phone number validator, or adding shadows to thumbnails before saving them.

I think those things, when you can encapsulate them nicely in a class, belong to the Libraries folder. Or well, maybe not strictly, but I think going with this approach I'll be using CI as intended. I'll try to keep most of the database communication in seperate "model" files (the actual storing of, for example, that phonenumer), but I can see how some communication can just as well fit inside the library (get a range of valid area codes for the same phonenumber example)

As for the routes. I think i'll just have to think those over and, indeed, mess around with routes untill i come up with a decent "scheme" which covers all the actions and has a logical stream for easy reference.
#7

[eluser]wiredesignz[/eluser]
Page control (what to display) and user input logic should be in the controller. All other should be libraries or Models.
#8

[eluser]Hyra[/eluser]
Well yes.

So, again .. the phone number example. Would this be the way to set it up?

[Controller] contact.php
Code:
// Get posted vars, validation, etc.

// Call a library
$this->load->library('val_phone');
$is_valid_phone = $this->val_phone->check($this->validation->phone_number);

// Do something according to BOOL

[Library] val_phone.php
Code:
function check($nr) {
  // !! This is dodgy! OPTIONAL USE OF MODEL?
  $valid = $this->some_model->getRanges('phone_ranges');
  if(in_array(substr($nr, 0, 3), $valid)) {
     if(reg_exp('#4/\g\n.gdd[3]d')) {
        return TRUE;
     }
  }
  return FALSE;
}

[Model] not_sure_what_to_call_it.php
Code:
function getRanges($from) {
   // Do database stuff
   return $array;
}

So this would mean the library depends on a model as well, thus not making it very portable. That's what was confusing me. Should the library contain database actions like the above, or should it really really go into a model, even though it only contains one simple database function.

Putting the db query inside the library would make it far more plug 'n play.
#9

[eluser]wiredesignz[/eluser]
Your library is redundant, both check and get_ranges should be in your phone_number model.

The phone number is a real world thing, the model would respond to the controller that the number is a valid phone number and be able to provide a range of valid numbers.
#10

[eluser]xwero[/eluser]
Why isn't a model as portable as a library? At some point in you code you need to access the actual field of the actual table of the actual database. If you put these actual values in the library you have to change the library code. If you put it in a model you have to change them in the model. If you do this
Code:
function check($nr)
{
    $query = $this->ci->db->get('phone_ranges');
    $valid = array();
    foreach($query->result() as $row)
    {
        $valid[] = $row['range'];
    }
    if(in_array(substr($nr, 0, 3), $valid)) {
     if(reg_exp('#4/\g\n.gdd[3]d')) {
        return TRUE;
     }
  }
  return FALSE;
}
You can only use that query in that library. If you put it in a model you can call the query in any library you want.

I will go further with the example you provided. You want to add a custom rule to the validation library. Therefore you can extend the validation library with application/libraries/MY_Validation.php
Code:
class MY_Validation extends CI_validation
{
    function MY_Validation()
    {
       parent::CI_validation();
    }

    function valid_phone($str)
    {
        $valid = $this->Validationmodel->getRanges('phone_ranges');
        if(in_array(substr($nr, 0, 3), $valid)) {
            if(reg_exp('#4/\g\n.gdd[3]d')) {
                 return TRUE;
            }
        }
        return FALSE;
    }
}
Now it you can use this function just like a regular rule (don't forget to add the rule to the language file). If you run multiple apps of one CI all your apps have instant access to that custom rule. If the different apps use different database structures you can define a constant in your bootstrap file to identify the app and in your model you can do
Code:
function getRanges()
{
    switch(APPNR)
    {
        case 1:
          $tablename = 'table1';
        case 2:
          $tablename = 'table2';
    }
    $query = $this->ci->db->get($tablename);
    $valid = array();
    foreach($query->result() as $row)
    {
        $valid[] = $row['range'];
    }
    return $valid;
}

If you put the database code in the library you would have to change the code there making the amount of code bigger. I prefer short files in spite of the fact i do a search for the method i want to change.

Models are a great way to separate data actions from user actions and to keep your code easy to maintain.




Theme © iAndrew 2016 - Forum software by © MyBB