PHP & Web Development Blogs

Search Results For: functionality
Showing 1 to 5 of 6 blog articles.
610 views · 3 months ago

![](https:/ /cdn.filestackcontent.com/hcg006yQ5q354UljJHdD)

Welcome back! If you're new to this series have a look at [Part 1 here](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql)

Today we are going to beef things up a bit and we will focus on the backend and some key CMS functionality.

It's time to get excited, this is where you'll start to see your barebones structure morph into something extraordinary!

Tired of my intro? That's ok! Let's jump into it!

## Getting the DB on board

Before we delve into this, it's imperative that we take a minute and plan things out.

The database tables that are vital to any CMS are the menu, the user table, and the content table.

Our menu table will start of as follows:

```

CREATE TABLE 'mydbname'.'menus' ( 'ID' INT(11) NOT NULL AUTO_INCREMENT , 'menuname' VARCHAR(100) NOT NULL , 'item' VARCHAR(50) NOT NULL , 'itemlink' VARCHAR(100) NOT NULL , PRIMARY KEY ('ID')) ENGINE = MyISAM COMMENT = 'menu table';

```

Let's break this down a bit.

In the SQL above, we're creating a new table called menus.

Essentially our structure looks like this:

ID | Menuname | Item | Itemlink

Our ID field is our unique identifier (our PRIMARY KEY).

Tip: Remember, you can use raw SQL or a tool like PhpMyAdmin to create your db tables/execute SQL queries.

Next up is our user table.

```

CREATE TABLE 'mydbname'.'users' ( 'ID' INT(11) NOT NULL AUTO_INCREMENT , 'username' VARCHAR(100) NOT NULL , 'password' VARCHAR(50) NOT NULL , 'email' VARCHAR(100) NOT NULL , PRIMARY KEY ('ID')) ENGINE = MyISAM COMMENT = 'user table';

```

Visually represented this structure looks like this:

ID | Username | Password | Email

Our ID field is our unique identifier.

And finally, our content table modifications. You probably remember creating a rudimentary content table in [Part 1](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql) of the series.

```

ALTER TABLE 'mydbname'.'content' ADD content_type VARCHAR(50);

```

Yep, you guessed right, in the above statement we are altering our content table and adding a new field called content type.

Our new table structure now looks like this:

ID | Title | Content | Author | Content Type

## Planning to Add to the Backend

Next , we're going to add a menu section, an add user section, and we'll also modify our content section.

Let's do this! reate a file called menus.php in your backend folder.

Next, code a HTML form to save your menu data.

The form needs the following fields:

Menu Name (we called this menuname in our db table).

Menu Item Name (we called this item in our db table).

Menu Link (we called this itemlink in our db table).

Try to follow [Part 1](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql) to do this on your own.

If you get a little stuck, that's ok. You can also follow the example below:

```

<form method="post" action="<?php $_SERVER['PHP_SELF'];?>"/>

<input type="text" name="menuname" class="mytextbox" placeholder="Menu Name" required />

<input type="text" name="item" class="mytextbox" placeholder="Item" required />

<input type="text" name="itemlink" class="mytextbox" placeholder="Item Link" required />

<input type="submit" value="Save Menu Item" name="savemenu" class="mybutton"/>

</form>

```

Notice the use of CSS classes? The gravy!

This will come in handy in our next tutorial.

Next, let's add the form processing code as we need to save these fields to the database. Remember to use the sanitization technique you learned in Part 2.

Add this above your `<form>` tag.

```

<?php

if(isset($_POST['savemenu'])){

include('../includes/conn.php');

if ($letsconnect->connect_error) {

die("Your Connection failed: " . $letsconnect->connect_error);

}else{

$menuname = $letsconnect ->real_escape_string($_POST['menuname']);

$item = $letsconnect -> real_escape_string($_POST['item']);

$itemlink = $letsconnect->real_escape_string($_POST['itemlink']);

$sql = "INSERT INTO menus(menuname,item,itemlink) VALUES ('".$menuname."', '".$item."', '".$itemlink."')";

if (mysqli_query($letsconnect, $sql)) {

echo "Your data was saved successfully!";

} else { echo "Error: " . $sql . "" . mysqli_error($letsconnect);

} $letsconnect->close();

}

}

?>

```

Ok phew, the menu data capturing section is done.

Let's move on to the user data capturing section, and modify the content capturing screen.

Repeat the steps above and create these two screens. Remember to keep an eye out for our database field names that we defined earlier! If you get stuck, look at the end result below:

Create adduser.php in your backend folder.

Create your data capturing form.

```

<form method="post" action="<?php $_SERVER['PHP_SELF'];?>"/>

<input type="text" name="username" class="mytextbox" placeholder="Username" required/>

<input type="password" name="password" class="mytextbox" placeholder="Password" required />

<input type="email" name="email" class="mytextbox" placeholder="Email" required />

<input type="submit" value="Save Menu Item" name="saveuser" class="mybutton"/>

</form>

```

Add your PHP processing code, remember the security!

Add this above your `<form>` tag.

```

<?php

if(isset($_POST[‘saveuser])){

include('../includes/conn.php');

if ($letsconnect->connect_error) {

die("Your Connection failed: " . $letsconnect->connect_error);

}else{

$menuname = $letsconnect -> real_escape_string($_POST[‘username']);

$item = $letsconnect -> real_escape_string($_POST[‘password']);

$itemlink = $letsconnect -> real_escape_string($_POST[‘email']);

$sql = "INSERT INTO menus(username,password,email) VALUES ('".$username."', '".$password."', '".$email."')";

if (mysqli_query($letsconnect, $sql)) {

echo "Your data was saved successfully!";

} else { echo "Error: " . $sql . "" . mysqli_error($letsconnect);

} $letsconnect->close();

}

}

?>

```

> Please note that I will be covering Password security in the tutorials that follow.

Make sure that you are using your localhost server to complete this tutorial series. Do not publish your work until you complete this series.

Lastly, let's move to our content capturing screen which is currently found in index.php in the backend folder.

We will be changing this to a more professional dashboard in the tutorials that follow!

**Our current file looks like this:**

```

<html>

<head><title>Backend - Capture Content</title></head>

<body>

<?php

if(isset($_POST['savedata'])){

include('../includes/conn.php');

if ($letsconnect->connect_error) {

die("Your Connection failed: " . $letsconnect->connect_error);

}else{

$title = $letsconnect -> real_escape_string($_POST['title']);

$content = $letsconnect -> real_escape_string($_POST['content']);

$author = $letsconnect -> real_escape_string($_POST['author']);

$sql = "INSERT INTO content (title,content,author) VALUES ('".$title."', '".$content."', '".$author."')";

if (mysqli_query($letsconnect, $sql)) {

echo "Your data was saved successfully!";

} else { echo "Error: " . $sql . "" . mysqli_error($letsconnect);

} $letsconnect->close();

}

}

?>

<form action="<?php $_SERVER[‘PHP_SELF'];?>" method="post">

<input type="text" name="title" placeholder="Content Title here" required/>

<textarea name="content">Content Here</textarea>

<input type="text" name="author" placeholder="Author" required/>

<input type="submit" value="Save My Data" name="savedata"/>

</form>

</body>

</html>

```

We need to modify this slightly to include our new field, content_type.

Add the input field in your `<form>` above the submit button.

```

<input type="text" name="content_type" placeholder="Content Type" required/>;

```

Next, add the content_type to the sanitization lineup.

```

$content_type = $letsconnect->real_escape_string($_POST['content_type']);

```

Lastly, store this variable to the database by modifying the $sql.

```

$sql = "INSERT INTO content (title,content,author,content_type) VALUES ('".$title."', '".$content."', '".$author."', '".$content_type."')";

```

## Conclusion

Chopping and changing is not always as daunting. Find a rhythm. There are many ways to make cumbersome coding a breeze and we will delve into that in the tutorials to come.

## Challenge

Think of ways to test what we just did through retrieving and echoing data from the database.

## Next Up: #CodeWithMe Part 5 Building a good base Continued

1526 views · 6 months ago

![](https:/ /cdn.filestackcontent.com/Ve0Q3jp4S4KuL2N4Mub7)

#### Welcome back! If you’re new to this series have a look at [Part 1 here](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql)

Today’s focus is on templating, the aesthetic that will make or break your web application.

Having a clean design with well defined CSS that’s responsive and user friendly goes a long way.

Developers often stick to their lane but delving into templating will bode in your favor, you can indeed

create a functional and launch-worthy application all on your own!

Let’s jump into it!

## Structured structure

Everything you tackle should be found with ease down the line. Therefore careful planning is fundamental to the success and sustainability of your project. You’ll also find that clearly defining your work lends itself to more productivity overall as you spend less that explaining your work during a handover / looking for a specific piece of code or resource. You’ll probably end up spending more time on actual work.

Finding your own unique pattern with file structure and CSS identifiers will also work in your favor as something unique to your process will most likely be easier to remember and form a tactile relationship with.

Our project’s current structure looks like this:

![](https:/ /cdn.filestackcontent.com/yvGBC8qbRMmsHklihrq2)

>If you need to backtrack, [Part 1](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql) is a great place to start!

In part 1, we created our index.php which displays info from our database.

Let’s take this a step further and create a header and a footer for our index.php

Create a file called header.php and save this to your includes folder.

Next, create a file called footer.php and save this to your includes folder.

Your file structure should now look like this.

![](https:/ /cdn.filestackcontent.com/8xTDBQkrTtSoZHC1aW5o)

### A header above all the rest

The header file will be a file we reuse throughout your web application. This file will contain important information that’s vital to the functionality and aesthetic of your website.

The type of info you’ll expect to see in a header.php file:

Script includes

Such as JQuery and important libraries

CSS includes

CSS files loaded from internal or external sources

Meta information

Contains important information that’s readable by search engines.

The basic structure of the beginning of your app, including your menu, and your logo.

For now, how header is going to have a basic layout.

Let’s get our HTML on!

```

<html>

<head>

<title>My Awesome CMS – Page Title</title>

</head>

<body>

```

### A footer that sets the bar

Create a file called footer.php and save it to your includes folder (yourcms/includes/footer.php).

Add this code to your new file.

```

</body>

</html>

```

### Next, let’s focus on the gravy… The CSS

CSS, when written beautifully, can truly set you apart.

You can tell your web application to load various styles to specific elements by defining unique identifiers.

Styles that are only used once are denoted with a # (a CSS “ID”) whereas styles that are reused multiple times are denoted with a . (a CSS “class”)

The best way to delve into the realm of CSS is to learn by experience.

### Let’s create!

First, we need to create and load our CSS file. Remember our nifty new pal header.php? This created a convenient way to load our CSS file!

Add the following code to your header.php just above the `</head>` tag.

```

<link href=”../assets/css/style.css” type=”text/css” rel=”stylesheet”/>

```

The ../ in the link to our stylesheet means we have to leave the current directory (the directory that header.php is in) and look for the assets/css/ directories.

Go ahead and create the css folder under your assets folder.

Next we’re going to create some simple CSS to test things out.

### It’s time to add some style!

We are going to create two divs.

A div is a divider / section in HTML.

Add this to your index.php (located in your CMS’ root folder) above the `<?php` tag.

```

<div id="myfirstid"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

<div class="myfirstclass"></div>

```

Then, create a CSS file

Add this:

```

#myfirstid{

Background:lightblue;

Font-family:Arial;

Font-size:44px;

Font-weight: Bold;

}

.myfirstclass{

Font-size:15px;

Color: darkblue;

}

```

Save your newly created CSS to assets/css/ as style.css.

### Pulling it all together, let’s see what we can do!

Let’s apply what we just learned to our index.php. But first, we should add our header.php and footer.php files.

### Including everyone

Add this to the top of your index.php file:

```

include(‘includes/header.php’);

```

Remove the `<divs>` we used for practice earlier, we have something better in store!

Add this to the bottom of your index.php:

```

include(‘includes/footer.php’);

```

Next, let’s modify our code so we can add some style to the data we retrieve from our database.

Modify the following line:

```

foreach($getmydata as $mydata){ echo "Title: "; echo $mydata['title']; echo "<br/>"; echo "Content: "; echo $mydata['content']; echo "<br/>"; echo "Author: "; echo $mydata['author']; echo "<br/>"; echo "<br/>";

```

as follows:

```

?>

<div id=”myfirstid”>

<?php

foreach($getmydata as $mydata){

echo "<div class=”myfirstclass”>Title: ";

echo $mydata['title'];

echo "<br/>";

echo "Content: ";

echo $mydata['content'];

echo "<br/>";

echo "Author: ";

echo $mydata['author'];

echo "</div><br/><br/>";

}?>

</div>

<?php

```

Your full index.php should now look like this:

```

<?php

include('includes/header.php');

include('includes/conn.php');

if ($letsconnect -> connect_errno) { echo "Error " . $letsconnect -> connect_error;

}else{

$getmydata=$letsconnect -> query("SELECT * FROM content");

?>

<div id="myfirstid">

<?php

foreach($getmydata as $mydata){

echo "<div class=”myfirstclass”>Title: ";

echo $mydata['title'];

echo "<br/>";

echo "Content: ";

echo $mydata['content'];

echo "<br/>";

echo "Author: ";

echo $mydata['author'];

echo "</div><br/><br/>";

}

?>

</div>

<?php

}

$letsconnect -> close();

include('includes/footer.php');

?>

```

## Go ahead, test it out!

There’s a lot to unpack and I will break things down a little more during our next tutorial!

## Challenge

Study the final index.php and try to form a few theories about why closing a php tag is necessary before adding raw html.

## Next Up: #CodeWithMe Part 4: Building A Good Base

1824 views · 6 months ago

![](https:/ /cdn.filestackcontent.com/ZriVX3EQNqmKgVF9FEdy)

#### Welcome back!, if you’re new please be sure to read [Part 1 here](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql).

This tutorial will focus primarily on Security and will touch on how to plan functionality.

Planning out an application and seeing progress regularly is a good strategy as you are most likely to complete your tasks in a timely fashion with this approach.

Ready?, ok let’s jump into it!

### DISCLAIMER

> We highly recommend that you follow these tutorials on a localhost testing server like Uniserver. Read through [Part 1 here](https:/ /nomadphp.com/blog/1925/code-with-me-challenge-custom-cms-development-with-php-and-mysql) to look at our recommendations. These tutorials follow a phased approach and it is highly recommended that you do not make snippets of code live prior to completing this tutorial series.

## Where we left off – the serious stuff.

In the previous tutorial we saved variables to the database.

It’s important to note that further steps are needed to ensure that data transactions to / from the database are secure.

A great first step is to ensure that all POST data (data transmitted after a user clicks a form’s submit button) is sanitized.

## What we’re trying to prevent

One of the most common exploits is SQL Injection, an attack most commonly used to insert SQL into db queries. POST data that’s not sanitized leaves a huge security hole for malicious exploits. In some cases SQL injection can be leveraged to rage an all out assault on a server’s operating system.

A few examples of a basic version of what this might look like can be seen below.

![](https:/ /cdn.filestackcontent.com/GdjoE6bPRQOT582LSGNQ)

#### OUTCOME

This might delete your database table

![](https:/ /cdn.filestackcontent.com/MlAzWxaJQWqsy7MjFQiM)

#### OUTCOME

This might provide access to the entire user table and the password protected area/dashboard.

***Please note that there are various types of SQL injection techniques and I will delve into this during the course of this series.***

## So what exactly is sanitization and what does it do?

When sanitizing POST data, we are essentially looking for any special characters that are often used in SQL injection attacks.

In many ways, this tiny piece of code is the unsung superhero of many database driven applications.

## Let’s secure that POST data!

Navigate to your backend folder and open index.php

Locate the following line of code:

```

$sql = "INSERT INTO content(title,content,author)VALUES ('".$_POST["title"]."', '".$_POST["content"]."', '".$_POST["author"]."')";

```

Ok, let’s get to work.

Based on what I mentioned a few moments ago, it’s clear that our SQL statement is vulnerable so we need to sanitize the POST data pronto!

The method I will focus on first is $mysqli->real_escape_string. This will escape any special characters found in the POST data.

Add the following just above your $sql.

```php

$title = $letsconnect -> real_escape_string($_POST['title']);

$content = $letsconnect -> real_escape_string($_POST['content']);

$author = $letsconnect -> real_escape_string($_POST['author']);

```

Did you notice the use of `$letsconnect`? This was used because of our db connection defined in conn.php.

Our new query will look like this:

```

$sql = "INSERT INTO content (title,content,author) VALUES ('".$title."', '".$content."', '".$author."')";

```

Go ahead and replace the old `$sql`.

Phew!, we can breathe easy now.

## Next, let’s lighten things up a bit by focusing on functionality and aesthetics.

A phased approach is the best way to tackle projects of any size.

I tend to jot this down on paper before creating a more legible professional spec!.

Typically the phased approach lends itself to logical progression.

For example, over the next several days I will go over the following:

* Account Access

* The login process

* The registration process

* The password recovery process

* Frontend

* The look and feel

* Menus

* Sidebars

*Main Content

*Footer

* Backend

* Content Management

* Add/Edit/Delete

* Security

This will give us a good springboard to delve into more complex functionality.

The aesthetic I have in mind will be barebones at first with clean CSS practices (this will make life a whole lot easier when we have to make changes down the line!).

## Challenge :

Plan out your own CMS, think about the user interface and design choices you’d like to implement, and create a phased approach.

## Conclusion

I hope this tutorial encouraged you to think about security and understand one of the most common exploits. During the course of this series, you will receive the tools necessary to beef up security while maintaining your sanity!

#### Next up

##### CodeWithMe – Let’s go templating.

2177 views · 7 months ago

![](https://images.ctfassets.net/vzl5fkwyme3u/2onKLFlXK4GStdtncTzZiT/9b0b6c5c45bacad4b107264875514180/codewithme.png)

It took me quite some time to settle on my first blog post in this series and I found myself thinking about the most requested functionality in my career – The good ‘ol Custom CMS – typically geared towards clients that want a straight forward, secure solution that can be expanded upon in a modular format and that’s their IP.

This will be our starting point. A blank slate to build something epic with clean code and even cleaner design. And in the spirit of building from scratch, I will refrain from using classes or a framework. The main reasoning behind this is to truly get everyone acquainted with and excited about PHP development.

Join me as I transform rudimentary code into something extraordinary that can be morphed into just about any Content, PHP, and MySQL driven project. So without further ado, let’s jump into it!

### The bare necessities

If you’re just getting started with development, there’s a nifty bite sized server called [UniformServer](https://www.uniformserver.com/) that will be your best friend throughout your coding career. [PHPMyAdmin](https://www.phpmyadmin.net/) (an awesome visual db management tool) comes built in so if you’re looking for a work right out of the box solution, this is it.

Alternatively, you can opt for [XAMPP](https://www.apachefriends.org/index.html) or use an alternative server of your choice.

### Now here’s where the exciting stuff begins, mapping things out.

I don’t see this done/encouraged often enough. Feel free to grab a piece of paper to logically map out your steps or produce a rough draft of where you’d like this project to go.

In this tutorial, I would like to achieve the following:

![](https://cdn.filestackcontent.com/D0KhE3hEQbClPDYqChUm)

### DB, DB, Set up your DB.

This requires a bit of planning but let’s start of with the basic structure we need to see this through.

We are going to need a user table and a content table and are a few ways to tackle this.

If you’re using the PHPMyAdmin tool you can create your database, add user permissions (Click on Permissions after creating your database), and create a table with ease.

![](https://cdn.filestackcontent.com/PiEKcelYTFitGkAOuHhf)

If you’re like me and prefer to look at good ‘ol SQL then writing an SQL statement is the preferred approach.

```

CREATE TABLE `mydbname`.`content` ( `ID` INT(11) NOT NULL AUTO_INCREMENT , `title` VARCHAR(100) NOT NULL , `content` LONGTEXT NOT NULL , `author` VARCHAR(50) NOT NULL , PRIMARY KEY (`ID`)) ENGINE = MyISAM COMMENT = 'content table';

```

Understanding the SQL statement

In a nutshell we are creating a table with important fields. Namely:

#########################

ID | Title | Content | Author

#########################

The ID field is our unique identifier.

Now we can move on to the file structure.

### Everything has a place in the file structure game

You can use a structure that speaks to your coding style / memory.

I tend to use the following:

![](https://cdn.filestackcontent.com/ZhJPGlmGQGKYM1WNsipR)

Choose a name for your CMS, which should be placed at the webroot of your localhost/server.

Replicate the folder structure as per the above example.

### Next, we’re going to create a basic connection file.

You can create a `conn.php` file in your root/includes folder.

The connection file will provide crucial information to connect to the database.

Type the following into your `conn.php` file, remember to include your own database credentials.

```

<?php

$letsconnect = new mysqli("localhost","dbuser","dbpass","dbname");

?>

```

### Let’s go to the homepage (index.php)

Create a file called `index.php` at the root of your CMS folder.

I will be adding comments in my code to help you understand what each line does.

Comments are a useful tool for developers to add important notes private to their code.

We need to pull information from the database so it’s imperative that we include our connection file.

```

<?php

include('includes/conn.php');

if ($letsconnect -> connect_errno) { echo "Error " . $letsconnect -> connect_error;

}else{

$getmydata=$letsconnect -> query("SELECT * FROM content");

foreach($getmydata as $mydata){ echo "Title: "; echo $mydata['title']; echo "<br/>"; echo "Content: "; echo $mydata['content']; echo "<br/>"; echo "Author: "; echo $mydata['author']; echo "<br/>"; echo "<br/>";

}

}

$letsconnect -> close();

?>

```

### Let’s get a (very) basic backend up and running

Create a file called `index.php` in your backend folder.

We need to create a basic form to capture our data.

Let’s code some HTML!

```

<html>

<head><title>Backend - Capture Content</title></head>

<body>

<form action="<?php $_SERVER[‘PHP_SELF’];?>" method="post">

<input type="text" name="title" placeholder="Content Title here" required/>

<textarea name="content">Content Here</textarea>

<input type="text" name="author" placeholder="Author" required/>

<input type="submit" value="Save My Data" name="savedata"/>

</form>

</body>

</html>

```

### Next, we need to process the form data.

Type the following just above the ```<form> ``` tag.

```

<?php

if(isset($_POST['savedata'])){

include('../includes/conn.php');

if ($letsconnect->connect_error) {

die("Your Connection failed: " . $letsconnect->connect_error);

}else{

$sql = "INSERT INTO content(title,content,author)VALUES ('".$_POST["title"]."', '".$_POST["content"]."', '".$_POST["author"]."')";

if (mysqli_query($letsconnect, $sql)) {

echo "Your data was saved successfully!";

} else { echo "Error: " . $sql . "" . mysqli_error($letsconnect);

} $letsconnect->close();

}

}

?>

```

> Note, this is a basic MySQL query to insert data. However, before using this in production it's important to add proper escaping and security to prevent SQL injections. This will be covered in the next article.

### Congrats you made it to the end of tutorial 1!

Test out your creation, modify your content, and play around.

Go to your sitename/index.php to see your frontend after capturing data via sitename/backend/index.php

### Next Up:

#codewithme Now With Security, Functionality, and Aesthetics in mind.

### Conclusion

Coding doesn’t have to be daunting and it’s my aim to divide a complex system into bitesized tutorials so you can truly use the knowledge you’ve acquired in your own projects.

4961 views · 1 years ago

![Working With Thin Controller And Fat Model Concept In Laravel](https://images.ctfassets.net/vzl5fkwyme3u/18L41PfcrcYYkM0qAsCous/7caca26b8cfb5a643d8cb16b14ae5eae/AdobeStock_147870533.jpeg?w=1000)

Models and controllers are one of the most essential programming handlers in the Laravel MVC framework, and both are used vastly for different functional operations. Models in Laravel are created inside the app folder and are mostly used to interact with the database using Eloquent ORM, while the controllers are located inside the directory App/Http/Controllers.

As a programmer, you should have the knowledge how to keep the balance in between the programming usage of Models and controllers. As which one should be more utilized for allowing functional tasks in applications deployed on any [PHP MySQL hosting](https://www.cloudways.com/en/php-cloud-hosting.php).

## What is the Concept of Thin Controller and FAT Models

The concept of the thin controller and fat model is that we do less work in our controllers and more work in our models. Like we use our controllers to validate our data and then pass it to the models. While in models, we define our actual functional logic and main coding operations of the desired application. This code structuring process is also a very basic concept of MVC and also the differentiating factor from the conventional complex programming which we mistakenly ignore sometimes.

## Why FAT Controllers Are Bad For Handling Code

Controllers are always meant to be defined short and concise, and it should only be used for receiving requests and return responses to it. Anything else further should be programmed in Models, which is actually made for main functional operations.

Placing functional logic in controllers can be bad for many reasons for your applications deployed on any _hosting for PHP_. As it not only makes code structure long but also makes it complex sometimes. Further placing code in Controllers is also not recommended because if same functionality is needed somewhere else in route, then pulling out the whole code from their becomes difficult and so its reusability in the application.

Though Laravel is an MVC framework while developing on laravel, we sometimes ignore this and write mostly all our code including the extending of App\Model and all our functional logic in controller route methods. What we can do here is we can create a sub model of our parent model. For example, our parent model is User then we can create another sub model of username in CustomerModel if you are using the same User model for all types of users. In this model, we will write all the logic related to user type Customer.

So now let's take an example of my existing blog creating comment system with laravel and vuejs. In that article, you can see I have made so much mess in my controller methods. Mostly, I have written all my comments logic in my methods, so to shorten that let's clean them in this article. Inside app folder, I will create a new file with name CommentModel.php. Inside this file, I will write my whole logic for comment functions. This is my basic file:

```php

<?php

namespace App;

use App\Comment;

use App\CommentVote;

use App\CommentSpam;

use App\User;

use Auth;

class CommentModel

{

}

?>

```

Right now it contains no function but has the reference of all my models which I required for this model. Let's first add a function named **getallcomments** passing **$pageId** as a parameter inside it. The function will get all the comments for the given page:

```php

public function getAllComments($pageId)

{

$comments = Comment::where('page_id',$pageId)->get();

$commentsData = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$replies = $this->replies($key->id);

$photo = $user->first()->photo_url;

/ / dd($photo->photo_url);

$reply = 0;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if(Auth::user()){

$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

if($voteByUser){

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if($spamComment){

$spam = 1;

}

}

if(sizeof($replies) > 0){

$reply = 1;

}

if(!$spam){

array_push($commentsData,[

"name" => $name,

"photo_url" => (string)$photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"reply" => $reply,

"votedByUser" =>$vote,

"vote" =>$voteStatus,

"spam" => $spam,

"replies" => $replies,

"date" => $key->created_at->toDateTimeString()

]);

}

}

$collection = collect($commentsData);

return $collection->sortBy('votes');

}

```

Now I will create another function named **replies** which takes **$commentId** as a parameter. The function is more or less programmed in the same manner as the upper function get all comments.

```php

protected function replies($commentId)

{

$comments = Comment::where('reply_id',$commentId)->get();

$replies = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$photo = $user->first()->photo_url;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if(Auth::user()){

$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

if($voteByUser){

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if($spamComment){

$spam = 1;

}

}

if(!$spam){

array_push($replies,[

"name" => $name,

"photo_url" => $photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"votedByUser" => $vote,

"vote" => $voteStatus,

"spam" => $spam,

"date" => $key->created_at->toDateTimeString()

]);

}

}

$collection = collect($replies);

return $collection->sortBy('votes');

}

```

Now lets create a function **create comment **which passes **$array** as a parameter in it:

```php

public function createComment($arary)

{

$comment = Comment::create($array);

if($comment)

return [ "status" => "true","commentId" => $comment->id ];

else

return [ "status" => "false" ];

}

```

Similarly, Now I will create all the function for comment in my **CommentModel**, so that all the functions gets accumulated in one model.

```php

<?php

namespace App;

use App\Comment;

use App\CommentSpam;

use App\CommentVote;

use App\User;

use Auth;

class CommentModel

{

public function getAllComments($pageId)

{

$comments = Comment::where('page_id', $pageId)->get();

$commentsData = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$replies = $this->replies($key->id);

$photo = $user->first()->photo_url;

/ / dd($photo->photo_url);

$reply = 0;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if (Auth::user()) {

$voteByUser = CommentVote::where('comment_id', $key->id)->where('user_id', Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id', $key->id)->where('user_id', Auth::user()->id)->first();

if ($voteByUser) {

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if ($spamComment) {

$spam = 1;

}

}

if (sizeof($replies) > 0) {

$reply = 1;

}

if (!$spam) {

array_push($commentsData, [

"name" => $name,

"photo_url" => (string) $photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"reply" => $reply,

"votedByUser" => $vote,

"vote" => $voteStatus,

"spam" => $spam,

"replies" => $replies,

"date" => $key->created_at->toDateTimeString(),

]);

}

}

$collection = collect($commentsData);

return $collection->sortBy('votes');

}

protected function replies($commentId)

{

$comments = Comment::where('reply_id', $commentId)->get();

$replies = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$photo = $user->first()->photo_url;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if (Auth::user()) {

$voteByUser = CommentVote::where('comment_id', $key->id)->where('user_id', Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id', $key->id)->where('user_id', Auth::user()->id)->first();

if ($voteByUser) {

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if ($spamComment) {

$spam = 1;

}

}

if (!$spam) {

array_push($replies, [

"name" => $name,

"photo_url" => $photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"votedByUser" => $vote,

"vote" => $voteStatus,

"spam" => $spam,

"date" => $key->created_at->toDateTimeString(),

]);

}

}

$collection = collect($replies);

return $collection->sortBy('votes');

}

public function createComment($arary)

{

$comment = Comment::create($array);

if ($comment) {

return ["status" => "true", "commentId" => $comment->id];

} else {

return ["status" => "false"];

}

}

public function voteComment($commentId, $array)

{

$comments = Comment::find($commentId);

$data = [

"comment_id" => $commentId,

'vote' => $array->vote,

'user_id' => $array->users_id,

];

if ($array->vote == "up") {

$comment = $comments->first();

$vote = $comment->votes;

$vote++;

$comments->votes = $vote;

$comments->save();

}

if ($array->vote == "down") {

$comment = $comments->first();

$vote = $comment->votes;

$vote--;

$comments->votes = $vote;

$comments->save();

}

if (CommentVote::create($data)) {

return true;

}

}

public function spamComment($commentId, $array)

{

$comments = Comment::find($commentId);

$comment = $comments->first();

$spam = $comment->spam;

$spam++;

$comments->spam = $spam;

$comments->save();

$data = [

"comment_id" => $commentId,

'user_id' => $array->users_id,

];

if (CommentSpam::create($data)) {

return true;

}

}

}

?>

```

Now we have all our required methods in **CommentModel**. So now let's clean up **CommentController** which is currently bit complex and lengthy in code structure. As right now **CommentController **look like this:

```php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Http\Requests;

use App\Comment;

use App\CommentVote;

use App\CommentSpam;

use App\User;

use Auth;

class CommentController extends Controller

{

/ **

* Get Comments for pageId

*

* @return Comments

*/

public function index($pageId)

{

/ /

$comments = Comment::where('page_id',$pageId)->get();

$commentsData = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$replies = $this->replies($key->id);

$photo = $user->first()->photo_url;

/ / dd($photo->photo_url);

$reply = 0;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if(Auth::user()){

$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

if($voteByUser){

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if($spamComment){

$spam = 1;

}

}

if(sizeof($replies) > 0){

$reply = 1;

}

if(!$spam){

array_push($commentsData,[

"name" => $name,

"photo_url" => (string)$photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"reply" => $reply,

"votedByUser" =>$vote,

"vote" =>$voteStatus,

"spam" => $spam,

"replies" => $replies,

"date" => $key->created_at->toDateTimeString()

]);

}

}

$collection = collect($commentsData);

return $collection->sortBy('votes');

}

protected function replies($commentId)

{

$comments = Comment::where('reply_id',$commentId)->get();

$replies = [];

foreach ($comments as $key) {

$user = User::find($key->users_id);

$name = $user->name;

$photo = $user->first()->photo_url;

$vote = 0;

$voteStatus = 0;

$spam = 0;

if(Auth::user()){

$voteByUser = CommentVote::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

$spamComment = CommentSpam::where('comment_id',$key->id)->where('user_id',Auth::user()->id)->first();

if($voteByUser){

$vote = 1;

$voteStatus = $voteByUser->vote;

}

if($spamComment){

$spam = 1;

}

}

if(!$spam){

array_push($replies,[

"name" => $name,

"photo_url" => $photo,

"commentid" => $key->id,

"comment" => $key->comment,

"votes" => $key->votes,

"votedByUser" => $vote,

"vote" => $voteStatus,

"spam" => $spam,

"date" => $key->created_at->toDateTimeString()

]);

}

}

$collection = collect($replies);

return $collection->sortBy('votes');

}

/ **

* Store a newly created resource in storage.

*

* @param \Illuminate\Http\Request $request

* @return \Illuminate\Http\Response

*/

public function store(Request $request)

{

$this->validate($request, [

'comment' => 'required',

'reply_id' => 'filled',

'page_id' => 'filled',

'users_id' => 'required',

]);

$comment = Comment::create($request->all());

/ / dd($comment);

if($comment)

return [ "status" => "true","commentId" => $comment->id ];

}

/ **

* Update the specified resource in storage.

*

* @param \Illuminate\Http\Request $request

* @param $commentId

* @param $type

* @return \Illuminate\Http\Response

*/

public function update(Request $request, $commentId,$type)

{

if($type == "vote"){

$this->validate($request, [

'vote' => 'required',

'users_id' => 'required',

]);

$comments = Comment::find($commentId);

$data = [

"comment_id" => $commentId,

'vote' => $request->vote,

'user_id' => $request->users_id,

];

if($request->vote == "up"){

$comment = $comments->first();

$vote = $comment->votes;

$vote++;

$comments->votes = $vote;

$comments->save();

}

if($request->vote == "down"){

$comment = $comments->first();

$vote = $comment->votes;

$vote--;

$comments->votes = $vote;

$comments->save();

}

if(CommentVote::create($data))

return "true";

}

if($type == "spam"){

$this->validate($request, [

'users_id' => 'required',

]);

$comments = Comment::find($commentId);

$comment = $comments->first();

$spam = $comment->spam;

$spam++;

$comments->spam = $spam;

$comments->save();

$data = [

"comment_id" => $commentId,

'user_id' => $request->users_id,

];

if(CommentSpam::create($data))

return "true";

}

}

/ **

* Remove the specified resource from storage.

*

* @param int $id

* @return \Illuminate\Http\Response

*/

public function destroy($id)

{

/ /

}

}?>

```

After cleaning up the controller it will look much simpler and easy to understand like this:

```php

<?php

namespace App\Http\Controllers;

use App\CommentModel;

use Illuminate\Http\Request;

class CommentController extends Controller

{

private $commentModel = null;

private function __construct()

{

$this->commentModel = new CommentModel();

}

/ **

* Get Comments for pageId

*

* @return Comments

*/

public function index($pageId)

{

return $this->commentModel->getAllComments($pageId);

}

/ **

* Store a newly created resource in storage.

*

* @param \Illuminate\Http\Request $request

* @return \Illuminate\Http\Response

*/

public function store(Request $request)

{

$this->validate($request, [

'comment' => 'required',

'reply_id' => 'filled',

'page_id' => 'filled',

'users_id' => 'required',

]);

return $this->commentModel->createComment($request->all());

}

/ **

* Update the specified resource in storage.

*

* @param \Illuminate\Http\Request $request

* @param $commentId

* @param $type

* @return \Illuminate\Http\Response

*/

public function update(Request $request, $commentId, $type)

{

if ($type == "vote") {

$this->validate($request, [

'vote' => 'required',

'users_id' => 'required',

]);

return $this->commentModel->voteComment($commentId, $request->all());

}

if ($type == "spam") {

$this->validate($request, [

'users_id' => 'required',

]);

return $this->commentModel->spamComment($commentId, $request->all());

}

}

}

?>

```

## Wrap Up!

So Isn't it looking much cleaner and simpler to understand now? This is what actually a thin controller and fat model looks like. We have all our logic related to Comment system programmed in our **CommentModel **and our controller is now just used to transfer data from the user to our model and returning the response which is coming from our model.

So this is how the structuring of the thin controller and fat model is made. Give your thoughts in the comments below.

SPONSORS