6
\$\begingroup\$

I have made a simple MVC framework of my own for my personal website to learn a thing or two about how this whole thing even works. I think I've got the idea, but there's one thing I'm not sure about.

Now I know that a model shouldn't need anything specific - everything has to be generalized so it's accessible from multiple controllers which do something different.

My main issue, though is: How the hell do I tell the model to save something the way I want it to? If it's generalized, it should have no information about any save table, any output message or any saving pattern to begin with.

Then I remembered that there's this new fancy thing in PHP called closures and this might be a good way to use them. I have decided to deal with validation in the model in this fashion:

Controller:

private function sendMail($data)
{
    $rebuilt['name'] = array("type" => "string", "value" => $data['name'], "required" => true);
    $rebuilt['email'] = array("type" => "email", "value" => $data['email'], "required" => true);
    $rebuilt['subject'] = array("type" => "string", "value" => $data['subject'], "required" => false);
    $rebuilt['message'] = array("type" => "string", "value" => $data['message'], "required" => true);

    $callback = function() use (&$rebuilt) {
        $headers   = array();
        $headers[] = "MIME-Version: 1.0";
        $headers[] = "Content-type: text/plain; charset=utf-8";
        $headers[] = "From: {$rebuilt['name']['value']} <{$rebuilt['email']['value']}>";
        $headers[] = "Subject: {$rebuilt['subject']['value']}";
        $headers[] = "X-Mailer: PHP/".phpversion();

        mail("some@email", $rebuilt['subject']['value'], $rebuilt['message']['value'], implode("\r\n", $headers));
    };

    $this->model->validateInput($rebuilt, $callback, 'contact', "SuccessEmailReceived", 'contact');
}

Model validateInput() method:

public function validateInput(&$validation, $function, $failAnchor = 'top', $successMessage = "GeneralActionSuccessful", $successAnchor = 'top')
{
    foreach ($validation as $key=>$value) {

        // trim the string before validation
        trim($validation[$key]['value']);

        if($value['required'] == true && !$value['value']) {
            $this->error = "ErrorFieldMissing";
            $this->anchor = $failAnchor;
            $this->formFields = $validation;
            return;
        }

        switch($value['type']) {
            case 'email':
                if(!filter_var($value['value'], FILTER_VALIDATE_EMAIL)) {
                    $this->error = "ErrorInvalidEmail";
                    $this->anchor = $failAnchor;
                    $this->formFields = $validation;

                    return;
                }

                break;
        }
    }
    // success, call the function passed
    $function();
    $this->success = $successMessage;
    $this->anchor = $successAnchor;
}

Basically, what this does, is the controller calls the model validateInput() method while passing the list of data for validation as a reference. An anonymous callback function, which also uses the same validation input by reference, is then called in the model. This way, no matter how the validator deals with the input array, the function behaves accordingly.

Please note that I only have email validation set up right now, because I don't need anything else. I just need to know if I'm doing things right, or if there's something I should re-learn.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

What is Model in MVC?

Now I know that a model shouldn't need anything specific - everything has to be generalized so it's accessible from multiple controllers which do something different.

A model is not a generalized concrete class, but a virtual layer that contains all business logic which in a good architecture would also contain it's own layers (application, domain and infrastructure) for more abstraction.

How to do specific things with a generalized model concrete class?

My main issue, though is: How the hell do I tell the model to save something the way I want it to? If it's generalized, it should have no information about any save table, any output message or any saving pattern to begin with.

Because it's not generalized (as I just explained above) this problem should now be solved.


Controller

The following diagram might give you a better visual picture of the (one of the possible) data flow in a MVC structure.

Do note that with the orthodox MVC pattern the Controller is not supposed to call or instantiate any views, but solely control the Model layer, nothing else. However, over the years this has changed due to I don't know what. But nowadays what you'll mostly see and hear is that a Controller's job is to control the model layer and call / return the appropriate view.

MVC Flow Digram

Your Case

I see you have a private sendMail() method in your Controller. Well, that doesn't belong there. In your model layer (specifically the application layer) I would have a class like EmailService that would contain this sendMail() method.

In your Controller you can now just get the needed parameters from a http request object and call $this->emailService->sendMail($data); or something of sorts. And finally call the appropriate view, if any (if you follow the contemporary MVC pattern that is).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.