Refactoring to MVC

Hi,

I have a relatively large internal web app I’ve built from scratch using PHP + MySQL over the last 18 months. I started off with a very basic knowledge of PHP and learnt as I went along, so some of my app is messy at best, while the newest parts start to implement design patterns. Mostly though, its been written page by page in a procedural manner with SQL queries, functions and HTML all smashed into one file per page.

I want to move it to an MVC architecture, but despite spending several days researching how to do so, I keep finding conflicting information between blogs or forum posts, which is putting me off refactoring in case I do something wrong and waste my time.

My current layout:

/public (contains index that points to front loader + JS files)
/app (contains front loader file + one procedural file per page)
– /classes (some logic stripped from pages)
– – /sql (individual file per DB table containing methods for each required result set)
– /template (header and footer HTML files with a little PHP mixed in)
– /vendor (third party libraries)

Would I be right in saying that I need to refactor to the following layout:

/public (no change - index points to front loader + JS)
/app (front loader file)
– /controller (front loader points her - file per page which calls model, then presents data to view)
– /model (methods to build data and handle POST data, results returned to controller)
– – /sql (no change - class file per DB table)
– /view (file per page containing HTML and display of data passed by controller)

I’m trying to get my head around the whole MVC concept, but with so many examples and conflicting advice, I’m struggling to piece together what I need to do.

Any help would be much appreciated. Please bear in mind that I’m self-taught in my spare time over the last 18 months, so my coding vocab is relatively simple and knowledge of architecture and patterns is minimal.

Cheers

Andy

2 Likes

Hey Andy,

I’d recommend giving this article a read: Symfony versus Flat PHP. Ignore the Symfony framework specific stuff towards the end - the first half is a good walkthrough of separating out a singe-file PHP script into different areas of responsibility.

If you wanna chat over any of the ideas there, or how to implement them in your app then feel free to post them and I (or other members) will be glad to help.

6 Likes

Hi Andy and welcome to the forum.

MVC is certainly the way to go and your structure looks good.

I would be tempted to try a Php Framework and can recommend CodeIgniter mainly because it has been on the go for about ten years. Support via their forum is also very user friendly. The installation is simple and you should be able to render the Welcome Page in a couple of minutes.

I find it is best to leave the existing application folder for reference and to point the index.php application folder to a working copy duplicate application folder suitably named. Gradually add your own pages and become familiar with the error logging system.

There are numerous other similar php frameworks available. Try some others and check out their support forums.

1 Like

Thanks fretburner and John_Betong !

John - I did look at CodeIgniter as a possibility about 10 months ago, but I wasn’t quite up to the skill level required to just pick it up and start working, so I decided to stick with my own code, as I can’t really afford the time to learn the framework. Its a possibility in future, but for now I’m going to refactor what I have, as its quicker in the short term and will make maintenance much easier going forward.

Fret - thanks so much for that Symfony tutorial link. I’ve had a snoop around the Symfony tutorials before, but gave it up as it was waaaay too advanced for my skillset at the time. However, that page you’ve directed me to was THE best explanation of MVC I’ve come across. Its so great because its so simple. Every other tutorial goes too far into the technical explanation and/or uses over the top code examples to work with that have confused me.

I now feel like I understand the MVC architecture well enough to start chopping up my app… in fact, that’s exactly what I’m about to do when I’ve finished writing this post.

I’m actually going to try a HMVC folder structure, as I think it may benefit me going forward if I can pull certain features off one page and display as part of another. It seems like an overly complex structure at the moment, but I suspect my app will become large enough in the future to warrant it.

Again - thanks so much for both of your inputs! And so much friendlier than stackoverflow (which I’m now boycotting).

Cheers

Andy

2 Likes

Out of interest, does anybody have any opinions on this HMVC folder structure, before I go too far down the road to undo it?

/public/ (JS + index points to front loader)
/app/ (front loader file)
– classes/ (methods that are likely to be used on multiple pages)
– – sql/ (class file per DB table)
– pages/
– – page1/ (model.php, view.php and controller.php)
– – page2/ (etc, etc)

I guess I’m asking because:

  1. Should there be a classes directory (as opposed to keeping the methods within the page models), and if so, should this sit somewhere else?

  2. Should the sql folder sit inside the classes directory or is this personal preference?

  3. Should I have a single file for model.php, view.php and controller.php or would there be a purpose in breaking them out by action and calling them something like action1Model.php, action1View.php, action1Controller.php, action2Model.php, action2View.php, etc.? I assume the answer to this is “it depends on how complex the pages are”, but I wanted to check in case there’s a best practice.

  4. As an alternative to the /pages/pageX/ structure above with a file per concern, would I be better having a separate sub-folder for each page action with its own model.php, view.php and controller.php file, or would this purely be personal preference?

  5. Have I missed anything out?

Cheers

Andy

1 Like

Arrghhh! Or what about the below structure instead?

/public/ (JS + index points to front loader)
/app/ (front loader file)
– classes/ (methods that are likely to be used on multiple pages)
– – sql/ (class file per DB table)
– pages/ (single controller.php per page, pointing to pageX model and view files in sub folder)
– – page1/ (action1model.php, action1view.php, action2model.php, action2view.php, etc.)
– – page2/ (etc, etc)

Would it be better practice or more logical or more/less messy to have a single controller pointing to a sub-folder per action?

Again, I suspect this is going to be personal preference or dependent on the complexity of the app…?

Cheers

Andy

1 Like

Maybe this flow diagram will help:

https://www.codeigniter.com/user_guide/overview/appflow.html

1 Like

Thanks John - yes, that does help a lot!

Based on that flow diagram, I assume that the directory and file structure is flexible, provided it conforms to the architecture? Therefore there’s no perfect way of doing it - just the way that seems most appropriate to the application?

1 Like

I realise this is going slightly off topic too, but …

In that flow diagram, security comes after routing. I was going to filter and sanitise all POST and GET inputs first and foremost, before anything else, at the top of the front loader script. I figure that this way, there’s less opportunity for malicious requests to make it deeper into the application and are filtered out before any processing takes place.

Would I be right here, or does it not matter, or is placing security after routing the correct/best practice method of doing so?

I can only offer a suggestion and think that it is OK to trap the security problems at that level.

As far as CodeIgniter is concerned there is a very neat feature which can easily set the /application//config/config.php → $config[‘log_threshold’] = 4; for information and error logging. Normally the threshold is set to 1 which only logs errors. The following threshold is set to 4 and shows the output to the log file:

Log file: /application/log/log-2017-07-15.php

<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>

INFO - 22:09:15 --> Config Class Initialized
INFO - 22:09:15 --> Hooks Class Initialized
DEBUG - 22:09:15 --> UTF-8 Support Enabled
INFO - 22:09:15 --> Utf8 Class Initialized
INFO - 22:09:15 --> URI Class Initialized
INFO - 22:09:15 --> Router Class Initialized
INFO - 22:09:15 --> Output Class Initialized
INFO - 22:09:15 --> Security Class Initialized
DEBUG - 22:09:15 --> Global POST, GET and COOKIE data sanitized
INFO - 22:09:15 --> Input Class Initialized
INFO - 22:09:15 --> Language Class Initialized
INFO - 22:09:15 --> Loader Class Initialized
DEBUG - 22:09:15 --> Config file loaded: /home/john/www/johns-jokes.com/application/config/config_ci_jokes.php
DEBUG - 22:09:15 --> Config file loaded: /home/john/www/johns-jokes.com/application/config/config_max_sess.php
INFO - 22:09:15 --> Helper loaded: url_helper
INFO - 22:09:15 --> Helper loaded: string_helper
INFO - 22:09:15 --> Helper loaded: inflector_helper
INFO - 22:09:15 --> Helper loaded: html_helper
INFO - 22:09:15 --> Helper loaded: text_helper
INFO - 22:09:15 --> Helper loaded: form_helper
INFO - 22:09:15 --> Database Driver Class Initialized
INFO - 22:09:15 --> Model Class Initialized
INFO - 22:09:15 --> Controller Class Initialized
INFO - 22:09:15 --> Image Lib Class Initialized
INFO - 22:09:15 --> File loaded: /home/john/www/johns-jokes.com/application/views/welcome_message.php
INFO - 22:09:15 --> Final output sent to browser
DEBUG - 22:09:15 --> Total execution time: 0.0359

This may seem over the top but as mentioned rather than re-inventing the wheel there are a lot of hidden security and helpful debugging features happening in the background when the /application/config/route.php file calls the appropriate /application/controllers/specific_control.php file. The specific_controller loads all the relevant $data (which may be none) and calls the relevant /application/view/specific_view.php file for rendering.

Caching can be set the /application/controllers/specific_controller.php -> $this->output->cache($n); where $n is the number of minutes to cache the file.

Welcome to the confusing world of programming styles :smiley: There have been lots of debates on MVC in PHP and the whole thing may look confusing, especially that the term MVC has been mostly misused in the PHP world being used to describe PAC or some other related pattern. Partly, this might be because MVC was meant for desktop applications and it needs some adaptation to the web.

I haven’t formally studied programming patterns so I don’t want to get into the debate what is MVC, PAC or some other acronym and which is better but I’d say any of those is much better than a non-structured application without any pattern. So it’s a good idea to have a look at a few PHP frameworks, gather some opinions from others and decide which one you like best and try it out.

The thing to have in mind is that a framework will not do everything for you - it will get you basic skeleton for your application and handle most basic and used stuff like routing, error handling, secured access with login credentials, database access, templating, etc. This is often quite a lot for a start because it can save you a lot of boring coding the same thing again and again.

But what I’m getting at is that even when you start using a framework you need to learn good programming practices because in a large application still your own code will be the heart of what it does, not the framework. So it’s a good idea to study good OOP concepts so that your code will be modular and not grow into a mess with time. One of concepts I found most useful was Dependency Injection.

What I also find useful is trying not to tie my code to the framework whenever possible. Obviously, some parts of my application will be tied to the framework but I try to keep that to the minimum. I attempt to write so that I can take my application (my controllers, models and views/templates) and move them to another framework without much effort. I imagine that in the future when some of my applications become really heavily used (!) and I need to scale - I may write my own very skinny framework and move everything there for performance reasons :smiley:

Instead of getting confused it’s important to do some research - but limited in time because this can last forever :). The funny thing I found is that the more experienced programmers are the more they are likely to disagree with one another - those with experience have strongest opinions on what is good or bad because they have experience - except every one is different so their perspective will differ. As an example you may scan this MVC vs PAC thread :slight_smile:

As to what I use - most often Silex. I don’t think there is any PHP framework that I particularly like, each one has some solutions that are over-engineered or I don’t like for some reasons so I’ve picked a microframework because it doesn’t get in my way too much. I also prefer plain SQL for database access rather than ORMs (which are offered by many frameworks) and this has worked pretty well for me. With time you will build your own preferences and programming style.

I don’t think the folder structure is the most important thing - just try to keep files organized in logical groups and you will be fine. Some frameworks may impose some folder structure on you.

And the last thing - apart from frameworks learn and begin using Composer if you haven’t started yet - it is a tremendous help in using existing libraries and also offers a very nice auto-loader for your classes - most often I enable psr-4 autoloading in Composer, which means the folder path is the namespace of the classes in that folder, for example file “App/Invoice/InvoiceIssuer.php” contains an InvoiceIssuer class in the namespace App\Invoice - this keeps things clean and organized. Composer is already used by most modern frameworks.

2 Likes

I recommend learning and using the factory pattern. I use object factories in my large applications and they are very powerful and useful. They help keep things consisitent and get a better global picture of your application. Remember OOP is a tool for code organisation and reuse. Best of luck!

1 Like

Thought I would explain how I use factories in order to give you a better clue.

$dataFactory = new DataFactory($db, $app);
$usersModel = $dataFactory->get("Users");
$userList = $usersModel->getList();

So the data factory is a singleton that has the mission of returning the instance of a data object. It stores the instances in an array so that if you request an existing instance it returns that instead of creating a new one. You may have to use the Users model from two separate components, in which case the factory will prevent you from creating 2 instances of the same object and running redundant operations (of course you would have to make the data factory instance available everywhere that is needed with a bit of thoughtful architecting). Great!
They also help shortening instantiation code as it will handle all of the includes. It also handles common dependency injection.
It goes further with some cool dynamic instantiation features, let me explain.

The Users object and any other data object models extend a common database object interface that holds all common functionality for those.

Also any particular app might feature custom extensions to e.g. the Users object model or any other. If the factory detects that there is an extension class for the requested object in the appropriate place it will instantiate that instead. Hence we can extend global common functionality for a specific site that uses your framework.

I hope that makes sense. Understanding the factory pattern is invaluable for large apps.

Because by using the factory pattern you have also kept things consistent with your data models then it becomes really easy to lay an API on top. Awesome!

1 Like

Interesting that you mention singletons because I was about to discourage the use of singletons. A singleton limits how an object can be instantiated and as a consequence makes it less flexible. Why use singletons when you can have a normally instantiatable (is there such a word?) object without artificial limits? You mention factories - they are the ones to decide if a class should have one instance or many, not the object being instantiated.

My short list of what to avoid in coding would be:

  1. Singletons
  2. Global variables
  3. Static methods
  4. Using the new keyword outside the factories or containers (sometimes hard to achieve this 100%)
1 Like

Yeah sorry for any confusion, what I meant by singleton is that you should only have one instance of the factory in your app, otherwise you wouldn’t be taking full advantage of it, not that I have technically enforced the limitation. You could have as many instances of the factory as you like but that would not prevent you from running operations more than once from different parts of your app

Ok, thanks for clearing this up, what I see most often described by a singleton is a class with a private constructor and a built-in mechanism preventing creation of multiple instances.

Sure, that makes sense, an app should have only one instance of a factory. What I meant is that there may be cases when you might want to run more than one instance of your whole application in a single request - in that case you could have multiple instances of the factory (one for each application instance), which makes each application instance an isolated environment, which is good. I know there are few use cases for this but I think it’s good to have this in mind when writing code because it directs us towards better OO solutions.

1 Like

Yes you’re right, my bad. Technically it is not a singleton and yes I agree with what you are saying. And would like to point out that even for things you would not expect factories to have a place in, they’re actually still very useful. For example my app features a page factory and at first sight you might only be expecting to have one page instance but pages have actually two ways of being instantiated: full and optimal. The app actually makes an optimal instance of every single page through the factory, in order to gather a navigation tree and other goodies.

Hello to everybody, this is my first post on sitepoint forum
I have sign up for different reasons but I find this topic interesting since matches another subject I’m studying a solution for.

Well in the past time I’ve studied Codeigniter and I quote who suggested that MVC framework.

  1. It won’t require you to install with composer or other dependecies tool. You’ll drop the codeigniter folder onto your htdocs and you are ready to go

  2. You’ll be able to re use your views (HTML + JS portions) of the existing pages

  3. As per the point 2., with slight modifications, you’ll be able to reuse your controllers (PHP portions) of the existing pages

  4. P.S. You are not obligated to use MODELS (either if sooner or later we (all) will) and you are not obligated to use a template language (though a template is available and can help having more readable code, though templates rely on javascript engines and I will try to avoid using templates in favour of vanilla javascript and php includes)

So… let’s go, try to “Codeigniter-ify” just the lighter one of your pages and you’ll discover the flexibility of Codeigniter.

Just bear in mind the Codeigniter’s VIEWs concept as it is explained in this blog post:

since until you won’t have clear and sharp the VIEW’ concept in your mind, what is the really simple mechanism of Codeigniter (and any MVC framework) , you’ll think about it that is too hard to deal with it, while it is not.

Then some dives into the Codeigniter’ routes (advanced) will complete the story.

Think about this:
I’m a toootal noob with PHP, Javascript a HTML, but in a matter of a bunch o hours (after explaining myself the VIEWS concept, the article linked above is self written by me to memorize the concept AND MAINLY because NOWHERE I have found it explained so simply as I think I have reviewed it) I have been able to implement also DataTables.net into a test view that I have done of an already existing database (my tickets database)

Believe me, that is the key point that all the CodeIgniter tutorials I have seen gonna confuse the reader: why? Because they tend to use the same names fo both controllers and views, and that generates misleadings.

Let me know if my blog helped

Cheers

I agree about the confusion and frequently clicked on the wrong file when editing. To overcome this I have adopted the principle of prefixing the Controllers wit **CI_**controller_name and the views with **v_**controller_name.

<?php 
declare(strict_types=1);

namespace App\Controllers;

use App\Libraries\MY_Lib;

//=========================================
// Controller
class Tests extends MY_Lib 
{

//===================================
public function test( $test='home', $tNo=NULL)
{
# DATA TO BE PASSED TO VIEW  
  $data =
  [
    'title'     => 'CI4 Playground by John_Betong', 
    'test'      => $test,
    'tNo'       => 5, // mt_rand(1,42);
    'menu'      => view('incs/menu'),
    'ci4_logo'  => $this->crunch(FCPATH .'assets/img/ci-logo.svg',   true),
    'style_tla' => $this->crunch(FCPATH .'assets/css/style_tla.css', true),
  ]; 

  echo view('incs/_header',   $data);
    echo view('tests/v_test', $data);
  echo view('incs/_footer',   $data);  

}//

}///===========================

Hi John, yes that is one point, but the BIG POINT is the one I focus in myself explanation:

VIEWs are NEVER “”“viewed”“” they are UNIQUELY INVOKED by CONTROLLERs

Until this concept won’t be “absorbed”, This will fake every and each MVC framework newbie

The fake enters in the game when the newbie will deal with the routes. At the begin, until the above concept won’t be clear and sharp, the newbie (I do it wrong still now sometime) will tend to use the views paths instead than the controlloers’ ones.

Isn’t it? :slight_smile:

I’m suprised that this is NEVER pointed out, it is so simple but you must elaborate this by yourself, never told in no one single tutorial, neither in the Codeigniter’s official one, and let’s think about that now Codeigniter is developed and maintained by a University!!! :-)))

University? Shouldn’t they teach? :expressionless: