0

EDIT: After some research, I saw this framework: this MVC framework. It have classes in Libs folder which are static (like Config, Session), can I use these ?


I am pretty new to MVC practices, and I am stuck on a weird problem..

I have many models, such as DB, User, Config, etc.. but I'm using many of these in each function I create.

I have a problem working with MVC patterns; I created multiple models, I'm using each one of them to handle grouped tasks(connection, DB, ect..).

Problem is, after creating the basic models, I ended up with code like this(within the controller).

class User
{
    function signup($username, $password, ...) 
    {
        $config = new Config();
        $DB       = new DB();
        $HTML     = new Session();
        // And so on...

        $canRegister = $config->get("registration-enabled");
        if ($canRegister and ..) {
            $this->username = $username;
            $DB->saveAccount($this);
            $session->setUser($this);
        } else {
            throw new Exception('bad signup');
        }
    }
}

I have to create instances of many models just for one or two functions.. but if the models are static, it should look like this:

class User
{
    function signup($username, $password, ...) 
    {
        $canRegister = Config::get("registration-enabled");
        if ($canRegister and ..) {
            $this->username = $username;
            DB::saveAccount($this);
            session::setUser($this);
        } else {
            throw new Exception('bad signup');
        }
    }
}

Note that many models doesn't use __construct method.. so is it good practice (or not bad) to have statics models in a MVC pattern ?

Please see EDIT above before responding.

MTC
  • 21
  • 1
  • 3
  • 3
    Static models doesn't make any sense. How would you have two users? As static objects are not instantiated, you can't have two instances of a "User" with a static user model. – Scopey Dec 09 '14 at 22:23
  • 1
    Static methods are global functions in disguise, so `DB::saveAccount` is essentially the same as `db_save_account()`. I personally don't see anything wrong with procedural programming, but if you want real OOP, this is not how it works. – georg Dec 09 '14 at 22:26
  • So how can I avoid creating instances of many models in each function ? – MTC Dec 09 '14 at 22:27
  • 2
    You don't. If you need to work with six different users in your code, you instantiate the User model six times. There are techniques for avoiding this with libraries like your database, configuration, session, etc. - for instance, if you're going to use the `DB` class in many different methods in your model, instantiate it once in the constructor. – Kryten Dec 09 '14 at 22:28
  • 1
    I recommend that you read the following article - http://code.tutsplus.com/tutorials/mvc-for-noobs--net-10488 (Ignore the title - it's a good article). What you're doing is syntactically correct, however, the correct way to do it is your second option. A framework such as Laravel, Yii etc would help you out a lot by taking care of most of this for you. Also note - that in your examples, it could be argued that they should be controllers rather than models. – Matt Burgess Dec 09 '14 at 22:31

1 Answers1

4

Model is a concept of abstraction!

Model consist of services, while services themselves consist of storage abstractions and objects that handle computations. Simply put, a service is a bridge between domain objects and storage abstractions (such as Data Mappers or Table Gateways). A model consists of those services.

That's a typical way how a model should be structured:

  Model
    - Storage
       - MySQL
          - YourMapper
    - Service
       - YourService

A class that handles abstraction to a table and does computation and validation is also known Anemic Model (which seems to be your case), because it violates the SRP and breaks Separation of Concerns.

When adhering to this right way, you can easily replace storage (say you can replace MySQL to MongoDB) since they no longer tightly-coupled to business logic. Or you can replace domain objects that handle computations without even touching a storage.

And no, nothing ever should be static!

For the purpose of example, let's imagine, that your write a library that does file uploading.

class Uploader
{
     ... 

     public function upload(array $files)
     {
         $path = Config::read('upload_path');
         $some_another_option = Config::read('foo');
         
         $this->move($path, $some_another_option, $files);
     }

     ...
}

So what kind of problem might lie here? Just remember that we write a library, and let's face these facts:

  • In order to use a uploading library, the Config object must be properly instantiated and its data must be fully loaded into the memory. Which is a waste of RAM and

  • What if you decide to replace Config to another source of required information? You can't because its tightly-coupled

  • If you want to distribute your library, you will also have to distribute your Config + its dependencies, which will make your library look bad.

Yeah, you probably have seen this approach in another frameworks. But popular doesn't mean correct, anyway.

The right way,

You gotta remember that object instantiation is another responsibility too. When you instantiate a Conifg you probably load data from somewhere (array or a table, whatever). So in your first approach you gotta load it n-times? That's seems a very wrong way to do.

What you should really do is to instantiate Config only once, and pass it to classes the require it, like this:

$config = new Conifg();
$config->load(__DIR__ . '/config_array.php');


$user = new User($config);

$system = new System($config);

// and so on, you got the point

The same applies to your DB and Session. Classes which use these objects should not bother about their instantiation. They just gotta bother how to use them.

Remember: Nothing ever kills code reuse-ability like Static classes and Singletons

All cool dudes refer to this technique as Dependency Injection

Community
  • 1
  • 1
Yang
  • 8,580
  • 8
  • 33
  • 58
  • But how to pass DB, Session, Mail,.. to most of these models ? – MTC Dec 10 '14 at 11:57
  • And do you have an example of an app/little framework running in proper MVC pattern with at least user management ? (without big framework like Symfony, etc.) – MTC Dec 10 '14 at 12:05