The untold truth I learned about frameworks
Tags: php, mysql, beginners, webdev
Published: 2021-04-24 12:57:36

__tl;dr__ :  No mater how much beautiful,sophisticated web systems you could  make by using frameworks, try doing everything by yourself manually once and you'll gain a huge insight as a developer. We learnt this throughout our group project and this is how.

#The Setting:

So exactly almost a year ago for our 2nd year curriculum , me and 3 others were allocated to a group (almost randomly :kissing_smiling_eyes:) and our module content was to create a web application for a real-world client. Sounds simple right? Well, the catch was,
 1. Since we did not go for a mobile app (which had to be done using native Android) Along with HTML and vanilla CSS we had to use either PHP or Java as the backend.

 2. We weren't allowed to use __ANY FRAMEWORKS__ .not even __Bootstrap__ .

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/owtq0bxfc3kl732rrurg.jpg)

In a modern society where even a 12-year-old simply uses `npx create-react-app my-app` to kick-start things, me and my teammates were baffled by why our lecturers wanted us to basically "reinvent the wheel" with technology that is almost obsolete now.

But being almost new to a project of this scale, we soon learned otherwise, and to this date consider this as __the best learning experience__ we had as beginner developers.

# Our project:

Repository link:
https://github.com/ov1n/Cleancar

The business idea was simple, A system for a car service station with 2 components where,

| User Role| Functionalities|
| ----------- | ----------- |
| Customer | Place a reservation from a  real-time time table |
| Employee | Apply for Lieu , and see statistics        |
| Receptionist| Place emergency reservation , add employee etc.|
| Manager | Could confirm/reject them and see statistics.|

### Other Functionalities:
- [PDF Generation for bills and reports](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jchws7y8a8046ri7jck.jpg)
- [Data visualization using charts and graphs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l1bslqd3f864l98lc6n1.png)
- [Notification alerts by SMS and e-mail](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl3501rgxatteg2s9s70.jpeg)

## Contributors:
- [Buthsara](https://github.com/MadhushankaUCSC)
- [Minuri](https://github.com/Minuri427)
- [Ovin](https://github.com/ov1n)
- [Tharindu](https://github.com/TharinduWithanage)

![what could go wrong](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oin9n27blihfq95h6zd7.gif)

##The architecture at-a-glance:

Since our rubric contained that marks will be awarded for the architectural pattern of the project, we chose MVC (at first over a Discord call within 5 minutes because it sounded awesome and we've heard of it in many Indian coding tutorials, but later had to know because of the questions we got in the interim presentation)

![Project was done using a modified MVC archtecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h8whlv9lse8qshgi67jo.png)

Well, we planned it out this way for the UI flows, there were a difference or two at the end
![UI flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f08yiosnp9kdv0p8z3ah.png)

#Where the disaster started (or fun began):

##CSS :relieved:

A main reason most of us use [bootstrap](https://getbootstrap.com/) or [tailwind](https://https://tailwindcss.com/) for a site is because they have responsive components. ever wondered how you hard-code responsiveness in CSS? It looks like this:

```CSS
@media screen and (max-width: 900px){
  .card{
    margin-left: 10%;
    width:80%;
  }
}

@media screen and (max-width: 800px){
  input[type=text], input[type=password], input[type=email], input[type=date],input[type=tel] ,input[type=time],select{
    margin-left: 2%;
  }
}

@media screen and (max-width: 750px){
  input[type=text], input[type=password], input[type=email], input[type=date],input[type=tel] ,input[type=time],select{
    width: 200px;
    
  }
}
``` 
Now think this being repeated and customized either by percentage or by pixel for seperate relevant classes in the website  :dizzy_face:

With tons of modified classes and without preprocessors we managed to get by a responsive layout. The credit should go to flexbox.

![ahh.. responsive :3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cw9vfbwp6ji72h9vc3k7.PNG)

And who said good data visualization can't be done without librarires :satisfied:
![leave report](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/517p0re54gkkvpea00i1.PNG)


### Lessons learnt and experience gained: 

- Making pages responsive with Vanilla CSS and flexbox
- Data Visualization without libraries 

## MVC?? :robot:

During our interim presentation when the panel asked us "Why do you use MVC?" and asked us to view the content of the __default controller and model__ we did not know the answers and afterwards we soon realized it has something to do with how the framework had been set-up in environments such as [CodeIgniter](https://codeigniter.com/) and [Laravel](https://laravel.com/) 

The solution :sleeping: : 

![Our Framework](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iiwokdqt6uu1xgfhe5dl.jpg)

So our framework basically has,

1. An autoloader for classes
2. A view loader in the default controller
2. A query builder for SQL functions
3. A router (to disable URL SQL injections)

The autoloader was made in the root folder included into the [index.php](https://github.com/ov1n/Cleancar/blob/master/code/app/index.php) to load the Classes by name.

```php
<?php
require_once './lib/routes.php';    //load routes

//to autoload classes,models and controllers
function __autoload($class_name){
    if(file_exists('./lib/classes/'.$class_name.'.php')){
        require_once './lib/classes/'.$class_name.'.php';
    }else if(file_exists('./Controllers/'.$class_name.'.php')){
        require_once './Controllers/'.$class_name.'.php';
    }
}
?>
```

The default controller was there to load the view and if there were additional parameters (passing of back-end, session variables etc.) it was overloaded in that respective controller. Since there are 4 user roles in the system and some had elevated privileges, with the help of session variables only the privileged role was allowed access to that page and otherwise redirected to a `403-Forbidden page`.
The `create_view` function in the default controller:

```php
public static function create_view($view_name,$role){
            
            if($role==""){
                //no permission needed
                require_once("./views/$view_name.php");
            }
            else if($role=="loggedin"){

                if(Session::get("role")){
                    require_once("./views/$view_name.php");
                }
                
            }else if(Session::get("role")==$role){
                require_once("./views/$view_name.php");
            }

            else{
                require_once("./views/error_403.php");
            }
        }
```
The function was called in the [routes.php] (https://github.com/ov1n/Cleancar/blob/master/code/app/lib/routes.php) file as,
```php
        Session::init();
        //logout if time is exceeded in session
        Login::timeout(Session::get("curr_time"));
        Manager::create_view('manager_home','manager');
```
For the _default model_ after including the database connection and methods for object instantiation (A constructor which calls the class in [app/lib/Database.php](https://github.com/ov1n/Cleancar/blob/master/code/app/lib/Database.php) to establish the connection), we implemented separate functions for each query type based on parameters provided.
Yes it's a simple string builder but it did the job for all Model functions :grin:
Following is the `SELECT` function and we considered the rest of queries too in the [app/models/Model.php](https://github.com/ov1n/Cleancar/blob/master/code/app/models/Model.php) to call the functions. 

```php
function select($arr,$tableName,$condition){
            //$condition= "WHERE custid=.......INNER JOIN...."

             //if arr is * select all from the table
             if($arr=="*"){
                $sql = "SELECT* FROM ".$tableName." ".$condition;
            
            //otherwise string concat the fields to select
            }else{

                $sql = "SELECT";
                //WHERE e='p' group by ................
                //if an array is the input get the fields
                if(gettype($arr)=='array'){

                    foreach ($arr as $elem) {

                        //if it's the last field comma is omitted
                        //SQL HAS ERROR IF LAST ELEMENT IS RECURRING BEFORE ITLL BE TAKEN AS FINAL ELEMENT
                        if($elem==$arr[count($arr)-1]){
                            $sql.=" ".$elem;
                        
                        //if not get all fields necessary for select
                        }else{
    
                        $sql.=" ".$elem.",";
                        }
                        
                    }
                
                //otherwise if its a string just append it without a loop
                }else if(gettype($arr)=='string'){

                    $sql.=" ".$arr;
                }

                
                $sql.=" FROM ".$tableName." ".$condition;
            }

            //echo($sql."\n");
            $result= mysqli_query($this->conn,$sql);

            //debugging
            if (!$result) {
                printf("Error: %s\n", mysqli_error($this->conn));
                exit();
            }

            return $result;

        }
```

The routing was done by the paths given in the [routes.php](https://github.com/ov1n/Cleancar/blob/master/code/app/lib/routes.php) file which are a compilation of calls to the functions in the [Route.php](https://github.com/ov1n/Cleancar/blob/master/code/app/lib/classes/Route.php).
The `.htaccess` file was rigged with regex to prevent SQL injections so a separate path was allocated for each page that was loaded.
This was a pivotal point as I was able to get a great understanding on general Regex programming.

### Lesson learnt and experience gained: 

- Handling of PHP variables and associative arrays (eg: `date=>time=> time_slots`)
- Folder structuring of files
![folder structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/me6l1joo4pe0rupfo26y.PNG)

## Real-time scheduling time-table (The Cherry on top) :cake: or my masterpiece :smirk:

As told earlier all of us had only _moderate-to-beginner_ experience in coding for big projects. JavaScript was also the same :unamused:. So as we superfluously included in our SRS that we will be having a component similar to the seat-booking system in Scope Cinemas (Guys, please brainstorm and only include what you CAN ACTUALLY DO in your projects.) as the time drew closer to the final demonstration shi* just got real :dizzy_face: .
Personally for me connecting `PHP` and `JavaScript` was like eating Butter Cake with Parippu.

But after almost 3 weeks of learning on-the-fly table creation, passing back-end PHP variables to JS variables, animation customization and event listeners the end product was like this:

![The customer reservation system](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1q5xk2w7855z3gh3oag.gif)

For vanilla CSS it's fancy right? Well, this is the just the back-end controller (without the rest of JS and model functions) of the calendar
```php
static function get_time_slots(){

            $timeslot=new Time_slot();
            $service_type=new Service_type();

            $min=$timeslot->get_min();
            $max=$timeslot->get_max();

            //get seperate timeslots for 3 slots 
            $full_service_slots=$normal_service_slots=$body_wash_slots=array();

            //get durations for service types
            $full_service_duration=$service_type->get_duration_from_name('Full Service');
            $normal_service_duration=$service_type->get_duration_from_name('Normal Service');
            $body_wash_duration=$service_type->get_duration_from_name('Body Wash');
            
            //full service
            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($full_service_slots,$curr);
                $curr=$timeslot->add_slots($curr,$full_service_duration);
            }
            
            //normal service
            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($normal_service_slots,$curr);
                $curr=$timeslot->add_slots($curr,$normal_service_duration);
            }

            $curr=$min;
            while(strtotime($curr)<strtotime($max)){
                array_push($body_wash_slots,$curr);
                $curr=$timeslot->add_slots($curr,$body_wash_duration);
            }
            //echo($normal_service_duration);
            //array_push($a,"blue","yellow");
            //set variables
            Session::set('full_service_slots',$full_service_slots);
            Session::set('normal_service_slots',$normal_service_slots);
            Session::set('body_wash_slots',$body_wash_slots);

            //get dates for the coming week
            $tomorrow = date("Y-m-d", strtotime('tomorrow'));
            Session::set('coming_week',Time_func::week_generate($tomorrow));
        }
``` 
Our project was on a car-service station which had platforms with different functionalities for different vehicles, so some had the ability to do Full-Service some didn't :confused: . Also these service types had different durations. Yes, practically an _NP scheduler problem_.

Now, After hours of scratching heads and slamming keyboards handling these on SQL got us queries like this:

```sql
SELECT timeslot_no
                    FROM time_slot
                    WHERE timeslot_no NOT IN (SELECT DISTINCT time_slot.timeslot_no
                    FROM time_slot,reservation_time_slot
                    WHERE time_slot.start_time>='$start_time' AND
                    time_slot.end_time<='$end_time' AND
                    time_slot.timeslot_no=reservation_time_slot.timeslot_no AND 
                    reservation_time_slot.date='$res_date') AND 
                    time_slot.start_time>='$start_time' AND
                    time_slot.end_time<='$end_time'
                    GROUP BY start_time;";
```

## Other stuff we managed to did:

Halfway through we realized that this is more of a _learning project_ . So why not try to do everything on our own to see how they work out? 

- Hashing Algorithm? We have our own one :smirk: (Credits to [Minuri](http://linkedin.com/in/minuri-wickramanayaka-b1b673200).) which randomizes byte by byte with an arbitrary number of cycles stored in a salt.
- Did you know even though PHP and MYSQL are used in almost all legacy stacks for development,  they don't share a mutual data type for time :dizzy_face:, Remedy? Hundreds of lines of code on these :
```javascript
function convert_to_12hour(time) {
  ...............
}

function date_validate(){
  ...............
}

//function to display date in needed format
function date_display(){
  .............
}

function addDays(date, days) {
  .........
}

//function to generate numerical values for upcoming week
function generate_week(days=7){
  ........
  
  return days;

}
```

- The only 2 libraries we used were the e-mail,SMS notifier and PDF generator. On a span of almost 5 working months with lectures alongside the 4 of us managed to hardcode every other aspect of it.

- Other separate classes we implemented with modularity include:
  - [Regex (Vehicle-numberplates)](https://github.com/ov1n/Cleancar/blob/master/code/app/lib/classes/Vehicle_regex.php)
  - [Session handler with custom functions](https://github.com/ov1n/Cleancar/blob/master/code/app/lib/classes/Session.php)
  - [Time functions] (https://github.com/ov1n/Cleancar/blob/master/code/app/lib/classes/util/time_func.php)
  -  Customized alert, confirmation boxes for wherever necessary
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mp3dhsjfvpkyeeiv82q8.JPG" alt="confirm boxes" width="300"/>

# Conclusion:

Is building a project of this scale a pain? __Yes!__ 
Is building a project without frameworks in this time a pain? ... __Really Yes__

But was all of this worth it? For me as a beginner developer __YES ALL THE WAY!__
Because :
 
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1p3viv7v3329jblpbgu7.jpg" alt="iron man" width="500"/>

 Again a huge thanks to our lecturers, our supervisor and co-supervisor who guided us through and every one who helped! Please feel free to point out any issues in the repo and feedback.

__The overall best experience gained:__ Working together as a team in the middle of a pandemic, in front of a computer screen :computer: going through an SDLC for the first time 

And if you are an undergrad who is boarding the same boat and feeling miserable if you are limited by the technologies provided in the rubric  well, you could build almost ANYTHING! and..
_if you CAN build anything, you shouldn't worry about anything right? :smirk:_
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7eq52mtl7dsvfy82wadm.jpg" alt="dream team" />