• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
MVC structural advice - separation of code

#11
[eluser]coffeeandcode[/eluser]
I haven't read the whole thread thoroughly, so apologies if I'm missing something..

[quote author="Lyon" date="1279818598"]
I think what you were meaning was something like :
Code:
$user = new User();
$user->username = "my_username";
$user->password = "my_password";
$user->Save();

I'm not really sure how that would work though.
Would it be something like :
...
[/quote]

No. If I'm understanding what you're trying to do, you'd do something like this:

Model:
Code:
class User extends Model {

    var $db;

    /**
     * I would not store the username and password in the class itself,
     * seems like a possible security issue, and would require updating if the
     * user changes their password.  I would just get it from the db each
     * time it's needed.
     *
     */

    function User() {
        parent::Model();

        $this->db = $this->load->database("default", true);
    }

    function add($data) {
        // add new user to db
    }

    function validate($data) {
       // validate given username and password with db
    }

    // etc
}

Users controller:
Code:
class Users extends Controller {

    function Users() {
        parent::Controller();
        $this->load->model("user");
    }

    function add($data) {
        // validate data
        $this->user->add($validated_data);
    }

    // etc
}

This would be for a user management system. ie, for what might be found at http://example.com/users/ for example.

For validation and logging in, I'd probably use an authentication library:

Code:
class Auth {

    function Auth() {
        $this->load->model("user");
        $this->load->library("session");

        // here check for a logged in user, if not redirect to log in page immediately.
        // that way none of the other classes need to worry about whether or not
        // the user is logged in.
    }

    function authenticate($data) {
        // call this function from your log in function

        if ($this->user->validate($data)) {
            // set session variable
        } else {
            // display error
        }
    }

    // etc
}

Oh, and as a note, I've never had a reason to use "New <class name>". Use $this->load.

#12
[eluser]coffeeandcode[/eluser]
One more thing, the basic rule of thumb I use for MVC is:

- any and all data access goes into a model (whether it's from a DB, XML file, RSS feed, or even just a PHP array)
- any and all html output goes into a view (html can be passed around in variables, but it is not sent to the browser until it gets to a view)
- everything else goes into a controller

The obvious exceptions to the last rule are things that aren't directly related to a data source - things that would normally go into a helper or library. But if it has data, the above 3 rules apply.

#13
[eluser]Lyon[/eluser]
[quote author="WanWizard" date="1279830556"][quote author="Lyon" date="1279818598"]I think what you were meaning was something like :
Code:
$user = new User();
$user->username = "my_username";
$user->password = "my_password";
$user->Save();
[/quote]
That is exactly how an ORM works, so no need to develop that yourself, there are plenty of ORM implementations around.[/quote]

Yeah, I've just started looking at doctrine, and can't believe how much simpler it makes all of this lol.
Thanks.

#14
[eluser]Lyon[/eluser]
@coffeeandcode
I'm not sure if that would have been what I wanted as the idea would have been to load more than one user at a time.
e.g.
Code:
$user1 = new User();
$user1->Load_From_Id(0);
$user2 = new User();
$user2->Load_From_Username("fred");

//Do something with the 2 users here

And as for never using new, the class wasn't a derivative from any codeigniter classes so it seemed wrong to load it from codeigniter, especially as there would need to be more than one instance.

Using new to create something adds it to the local scope, where as loading it using codeigniter creates the class using new and then stores a refrence to the class instance so that it can be accessed through whatever section of the global $this codeigniter has saved it to.

e.g. $this->admin_model

#15
[eluser]coffeeandcode[/eluser]
[quote author="Lyon" date="1279837537"]@coffeeandcode
I'm not sure if that would have been what I wanted as the idea would have been to load more than one user at a time.
e.g.
Code:
$user1 = new User();
$user1->Load_From_Id(0);
$user2 = new User();
$user2->Load_From_Username("fred");

//Do something with the 2 users here
[/quote]

Interesting. Why would you want to load 2 users at once? Is this from a user management perspective, or would you have 2 users logged in at once? I'm having a hard time understanding why one would want to do this.

In any case, I'd probably use one user model, and allow my load function to accept any number of ids and usernames. That way you don't need to worry about 2 instances of the class, and can benefit from using a model (which you really should be doing for data access). Doing it the way you've described would be a nightmare to maintain if you ever need to modify your interface to user data.. the code will be all over the place, instead of collected all in a users model. That's what models are for - to provide a "closed" interface to data.

ie:
Code:
class User extends Model {

    var $db;
    var $loadedUsers;    // collection of loaded users is kept within the model

    function User() {
        parent::Model();
        // db and any other initialization
    }

    function load($data = array()) {
        extract($data);

        foreach ($ids as $id) {
            // load by id
        }

        foreach ($usernames as $username) {
            // load by username
        }
    }
}

and to use it from your controller:
Code:
$this->load->model("user");

$users = array(
    "ids" => array(23, 17, 52),
    "usernames" => array("fred", "bob", "alice")
);

$this->user->load($users);

I guarantee you CI provides a neat and simple way to do almost anything. I don't see why one would ever need to use New and maintain their own classes. But I could be wrong - stranger things have happened Wink

#16
[eluser]Lyon[/eluser]
[quote author="coffeeandcode" date="1279839114"][quote author="Lyon" date="1279837537"]@coffeeandcode
I'm not sure if that would have been what I wanted as the idea would have been to load more than one user at a time.
e.g.
Code:
$user1 = new User();
$user1->Load_From_Id(0);
$user2 = new User();
$user2->Load_From_Username("fred");

//Do something with the 2 users here
[/quote]

Interesting. Why would you want to load 2 users at once? Is this from a user management perspective, or would you have 2 users logged in at once? I'm having a hard time understanding why one would want to do this.

In any case, I'd probably use one user model, and allow my load function to accept any number of ids and usernames. That way you don't need to worry about 2 instances of the class, and can benefit from using a model (which you really should be doing for data access). Doing it the way you've described would be a nightmare to maintain if you ever need to modify your interface to user data.. the code will be all over the place, instead of collected all in a users model. That's what models are for - to provide a "closed" interface to data.

ie:
Code:
class User extends Model {

    var $db;
    var $loadedUsers;    // collection of loaded users is kept within the model

    function User() {
        parent::Model();
        // db and any other initialization
    }

    function load($data = array()) {
        extract($data);

        foreach ($ids as $id) {
            // load by id
        }

        foreach ($usernames as $username) {
            // load by username
        }
    }
}

and to use it from your controller:
Code:
$this->load->model("user");

$users = array(
    "ids" => array(23, 17, 52),
    "usernames" => array("fred", "bob", "alice")
);

$this->user->load($users);

I guarantee you CI provides a neat and simple way to do almost anything. I don't see why one would ever need to use New and maintain their own classes. But I could be wrong - stranger things have happened Wink[/quote]

Users is just a simple example, it could be anything like Posts, Projects.
Maybe it's just me, but I've never seen class management as a hassle. It adds no real complexity.

In my example changing the interface would only require altering the functions inside the User class, same hassle as altering the model class, after all they are both just classes with functions and variables.

I mean I can see the advantage of having and using a model, and I do use them.
It just seems to me that any model will suffice, it doesn't need to be a CodeIgniter model.
For example I am starting to implement my site with Doctrine and using their Doctrine_Record as a model instead of the CodeIgniter model.

The CodeIgniter load model is helpful as it saves you from having to store the new my_model() in a variable and reference it that way, but besides that I see no obvious advantages for it.

Anyway as I have made the move to Doctrine for it's ORM using it as a CodeIgniter plugin I have now got a solution for this problem.

Thanks all.

#17
[eluser]WanWizard[/eluser]
Did you look at Datamapper?
Looks a lot easier to implement and use compared to Doctrine.

#18
[eluser]coffeeandcode[/eluser]
[quote author="Lyon" date="1279841159"]It just seems to me that any model will suffice, it doesn't need to be a CodeIgniter model.[/quote]

Fair enough.. I guess I just don't see the point in using a framework that provides things for you if you're going to rewrite them yourself. It kind of defeats the purpose. But to each their own! Good luck with your project :-)

#19
[eluser]Lyon[/eluser]
[quote author="WanWizard" date="1279842949"]Did you look at Datamapper?
Looks a lot easier to implement and use compared to Doctrine.[/quote]

Well I'm not sure if it's better or not, but the documentation looks fantastic Smile
I think I'll give it a shot and see if I can get it all set up properly.
The only downside I can see to it (apart from having to make sure everything is updated lol) is the strict table naming requirements, but I'm sure I can figure it out. Thanks for the link. :-)

One thing I'm unsure about after looking at the documentation though
Say I have :
a table catagories which has an id and a varchar catagory
a table posts which has an id and some other information
then a table catagories_posts which must have an id and catagory_id and post_id as the other fields

Would I have to manually check for duplicate entries or would datamapper do that for me?

Thanks!

#20
[eluser]WanWizard[/eluser]
If you have defined these three models, and the relationship between them, DMZ will check the relationship, and will do an update if it exists, or an insert if it doesn't.

If you would create a new object for catagories_posts, and would do a $catagories_posts->save() without having it linked to a catagory and a post, I'm not sure it would complain that it is missing some relationships. I'd have to try that.

EDIT: just tested it. It doesn't. It will create a junction record with foreign key values 0.


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


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