How to implement MVC style on my PHP/SQL/HTML/CSS code?
Do you have any suggestion on how to successfully seperate HTML/CSS from PHP/SQL?
Congrats for looking how you can improve code. That's the precondition, you need to want to improve it and the topic is lengthy. So your will is crucial.
I start lightly and then try to give some tips. As you're missing experience, look for one point to start with, most certainly the last one of the list below. But first things first:
To separate something from each other, you need to have some code that separates:
[HTML/CSS/PHP/SQL]
[HTML/CSS] <--> [SEPARATOR] <--> [PHP/SQL]
The Separator here actually is PHP code as well, but I think you get the idea.
As you can see only the Separator talks with HTML/CSS and PHP/SQL.
So both HTML/CSS and PHP/SQL need to have an interface with Separator (the line between) to make this work.
Normally in a program you pass around data that get's processed. The data is pretty dynamic and can have a compound complexity, especially if you pass data to an output routine that should format it properly.
There are multiple ways of how such a Separator (or multiple of them) can be written. You can layer your software or provide components that do things in their area or domain. E.g. you have a database layer or database component that takes care about the interaction with the database.
Or you have a templating engine that takes care to put your strings and arrays into some readable HTML.
In short this is the pasta theory of software design:
- Spaghetti code - all in one, code is heavily interwoven, preferable with Bolognese or Aglio, Olio e Peperoncino.
- Lasagne code - Layered, one layer has two other layers it interacts with (unless bottom or top), always with Béchamel sauce.
- Tortelini code - Small components that just do their job, they have Meat or Spicy Vegetables inside.
Like we eat different pasta in our lives, when programming we need to deal with all these different type of code as well, and we develop our own preferred taste over time. As a kid we're feed but over time we start to cook something our own and vary the recipes.
So I think it's a good point you just don't want to now eat MVC Framework X with much awesome for the next weeks only because somebody told you it's the way to eat now. And before eating, there is tasting, right? Not to mention fast-food, you know like these noodles with sauce in package - only add water. Urgh.
I don't know which data your output needs and what the input is. Following are some rough refactoring tips for applications that output HTML/CSS and interact with a MySQL database. This can not be a complete list and the descriptions can only roughly outline some thoughts:
- Move CSS out of HTML. Use selectors effectively in the linked CSS definition and replace any
style
attributes if you still have some. This makes your CSS code re-useable and more modular. It will help you to find flaws inside your HTML and to separate the Structure (HTML) from the Presentation (CSS). Effective HTML start with effective usage of CSS, those two are very powerful together and often this already will lighten your programs output routines. - Move business logic out of HTML. Both HTML and your code can be a beast, so better keep them apart. They have the tendency to fight with each other, and as both are very powerful, the fight will continue while you develop your application, that distracts you from the work you need to do.
Consider if you need to already have complex output inside your application or if you can just pass on arrays with subelements (a key is a var, a var can contain a string or number or another var-array). Normally that is all needed to pass even complex data into a view or template. You HTML then only needs to echo some array members and orforeach
over subarrays. This is a very simple technique to create a template. You can use PHP for it, so you're actually really flexible (just draw the border which code belongs into your view layer and which is part of the application, e.g. providing values for the view). - Move SQL out of your code. Move the database interaction code away. Create yourself one or multiple objects that have methods which return the data in a way you need (consume) it in your actual processing code, like
$component->getThatData()
which then returns data in a normalized form. Make those components then use a dedicated database component to talk over with the database. In your application code (business logic) only use the database component and preferably the objects you create to get the data, so you don't have any line of SQL any longer inside your main code. - Divide and Conquer your application code: Divide your code into Transaction Scripts. They are often easy to create from existing spaghetti code and will be probably become the said Separator you're looking for in middle terms. They will then have the role to process data and passing it on (into the output/view).
- Use clear language: If you have complex formatted string data that is not normalized, write yourself Parser classes that do the work for you and which can be easily re-used (if that's the case in your application). As you should look forward to minimize the use of plain SQL in your code, you should also look forward to move complex regular expressions away as well. Encapsulate what varies is a key point. Same applies to long routines to just handle some data (e.g. sort, order and arange it in another format), move them into components of each own and think about how you can make them accessible and re-useable.
- Make your code functioning: Find out about the logic how you invoke functionality in your program. You can try to separate functionality away from how it's invoked. E.g. some routine that invokes any of the Transaction Scripts. This might not be necessary if you request PHP files directly via the browser, as those are then your transaction scripts and the webserver takes care to resolve the command send via URL into your application to the transaction script. But you should then wrap any logic needed to process the incoming command and it's parameters into re-useable components (e.g. a Request class that contains standard code to get the URL and or variables from a HTTP request).
- Create a common entry-point by including the same file at the very top of all files that are called via the browser. You can then put common code (like setting up the application session state object and initializing the database component) into it, see as well Application Controller
- Remove duplication by looking for literally duplicated code. Wrap it into a function or class. Create a library folder for your own application into which you put your includes. If you follow a common pattern with Classnames and Namespacing, you can easily use an autoloader to keep inclusion easy. Make your library apart from third-party code. Place all third-party code into a library folder of it's own with one subdirectory for each third-party component.
- Use lightweight, existing components. Lightweight is important because you have your own code already, you don't want to turn and press it all at once onto a framework.
Existing is important because you don't want to re-invent the wheel. You will have enough work for your own refactoring your code. After you feel better about your application and you still have power and will, you can always write everything new. But if you're alone or in a small team, Existing is pretty powerful.
Simple libraries are for example:
- Templating engine: Mustache
- Database layer: NotORM
- Create Application State, e.g. as an object you can make use of in case some components need to know about the application state or each other without direct interaction. By default in PHP if you don't have one, global and global static variables are used to create state. However these variables can make your live hard as code grows. When you create an application state object, it's clear which components make use of it, access to it can be controlled (e.g. calling a method instead of reading a variable, which can help with debugging) and components as well can find out if it's the right time in the application flow to come into action. It's also a good tool for refactoring your code over time.
- Preserve a Working Application, keep your code in a state to run. Ideally this would be backed up by automatic tests. Consider that you need to rewrite much. For example if you start to integrate a database component, do it. Move all your existing code to it in one step. So who tells you it still runs? Use git for better undo and to test stuff. That's more important than choosing the right library. Preserving a working application is also always the key point because that's why you change it, right?
Why not use a templating engine? TWIG is very easy to use and great for this sort of thing. It is often used with the Symfony framework, but can easily be used on its own.